LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/3] powerpc: kdump: CPUs assume the context of the oopsing CPU
From: Michael Ellerman @ 2010-05-11  4:14 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, paulus, miltonm, linuxppc-dev
In-Reply-To: <20100511022551.GF12203@kryten>

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

On Tue, 2010-05-11 at 12:25 +1000, Anton Blanchard wrote:
> We wrap the crash_shutdown_handles[] calls with longjmp/setjmp, so if any
> of them fault we can recover. The problem is we add a hook to the debugger
> fault handler hook which calls longjmp unconditionally.
> 
> This first part of kdump is run before we marshall the other CPUs, so there
> is a very good chance some CPU on the box is going to page fault. And when
> it does it hits the longjmp code and assumes the context of the oopsing CPU.
> The machine gets very confused when it has 10 CPUs all with the same stack,
> all thinking they have the same CPU id. I get even more confused trying
> to debug it.

Lol, guess that one didn't get tested that well :)

Fix looks good.

cheers



[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH 1/3] powerpc: kdump: Fix NULL pointer dereference in irq disable code
From: Michael Ellerman @ 2010-05-11  4:14 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, miltonm, linuxppc-dev
In-Reply-To: <20100511022329.GE12203@kryten>

[-- Attachment #1: Type: text/plain, Size: 690 bytes --]

On Tue, 2010-05-11 at 12:23 +1000, Anton Blanchard wrote:
> With sparse irqs we have to check if we have a descriptor before dereferencing
> it.
> 
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> 
> diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
> index 6f4613d..5182439 100644
> --- a/arch/powerpc/kernel/crash.c
> +++ b/arch/powerpc/kernel/crash.c
> @@ -375,6 +375,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
>  	for_each_irq(i) {
>  		struct irq_desc *desc = irq_to_desc(i);
>  
> +		if (!desc)
> +			continue;
> +
>  		if (desc->status & IRQ_INPROGRESS)
>  			desc->chip->eoi(i);
>  

Ouch, my bad.

cheers

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* [PATCH] powerpc: Use more accurate limit for first segment memory allocations
From: Anton Blanchard @ 2010-05-11  4:59 UTC (permalink / raw)
  To: benh, mikey, miltonm; +Cc: linuxppc-dev

Author: Milton Miller <miltonm@bga.com>

On large machines we are running out of room below 256MB. In some cases we
only need to ensure the allocation is in the first segment, which may be
256MB or 1TB.

Add slb0_limit and use it to specify the upper limit for the irqstack and
emergency stacks.

On a large ppc64 box, this fixes a panic at boot when the crashkernel=
option is specified (previously we would run out of memory below 256MB).

Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
---

Some things we should add:

- Specify a more intelligent limit for BookE
- The allocation of the PACAs should use this limit too

Index: linux-2.6/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/setup_64.c	2010-04-22 17:23:42.000000000 +1000
+++ linux-2.6/arch/powerpc/kernel/setup_64.c	2010-04-30 09:46:15.000000000 +1000
@@ -424,9 +424,18 @@ void __init setup_system(void)
 	DBG(" <- setup_system()\n");
 }
 
+static u64 slb0_limit(void)
+{
+	if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
+		return 1UL << SID_SHIFT_1T;
+	}
+	return 1UL << SID_SHIFT;
+}
+
 #ifdef CONFIG_IRQSTACKS
 static void __init irqstack_early_init(void)
 {
+	u64 limit = slb0_limit();
 	unsigned int i;
 
 	/*
@@ -436,10 +445,10 @@ static void __init irqstack_early_init(v
 	for_each_possible_cpu(i) {
 		softirq_ctx[i] = (struct thread_info *)
 			__va(lmb_alloc_base(THREAD_SIZE,
-					    THREAD_SIZE, 0x10000000));
+					    THREAD_SIZE, limit));
 		hardirq_ctx[i] = (struct thread_info *)
 			__va(lmb_alloc_base(THREAD_SIZE,
-					    THREAD_SIZE, 0x10000000));
+					    THREAD_SIZE, limit));
 	}
 }
 #else
@@ -470,7 +479,7 @@ static void __init exc_lvl_early_init(vo
  */
 static void __init emergency_stack_init(void)
 {
-	unsigned long limit;
+	u64 limit;
 	unsigned int i;
 
 	/*
@@ -482,7 +491,7 @@ static void __init emergency_stack_init(
 	 * bringup, we need to get at them in real mode. This means they
 	 * must also be within the RMO region.
 	 */
-	limit = min(0x10000000ULL, lmb.rmo_size);
+	limit = min(slb0_limit(), lmb.rmo_size);
 
 	for_each_possible_cpu(i) {
 		unsigned long sp;

^ permalink raw reply

* Re: [PATCHv2 2/3] powerpc: Add power management support to VIO bus
From: Benjamin Herrenschmidt @ 2010-05-11  5:35 UTC (permalink / raw)
  To: Brian King; +Cc: linuxppc-dev
In-Reply-To: <201005102053.o4AKrFJL017810@d03av05.boulder.ibm.com>

On Mon, 2010-05-10 at 15:53 -0500, Brian King wrote:
> Adds support for suspend/resume for VIO devices. This is needed for
> support for HMC initiated hibernation.

Your previous version of that patch is already in powerpc-next. Please
make a new patch against it.

Cheers,
Ben.

> Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
> ---
> 
>  arch/powerpc/kernel/vio.c |    1 +
>  1 file changed, 1 insertion(+)
> 
> diff -puN arch/powerpc/kernel/vio.c~powerpc_vio_bus_pm arch/powerpc/kernel/vio.c
> --- linux-2.6/arch/powerpc/kernel/vio.c~powerpc_vio_bus_pm	2010-05-10 11:12:15.000000000 -0500
> +++ linux-2.6-bjking1/arch/powerpc/kernel/vio.c	2010-05-10 11:12:15.000000000 -0500
> @@ -1365,6 +1365,7 @@ static struct bus_type vio_bus_type = {
>  	.match = vio_bus_match,
>  	.probe = vio_bus_probe,
>  	.remove = vio_bus_remove,
> +	.pm = GENERIC_SUBSYS_PM_OPS,
>  };
>  
>  /**
> _

^ permalink raw reply

* Re: [RFC][PATCH 11/12] KVM: introduce new API for getting/switching dirty bitmaps
From: Takuya Yoshikawa @ 2010-05-11  5:53 UTC (permalink / raw)
  To: Marcelo Tosatti
  Cc: linux-arch, arnd, kvm, kvm-ia64, fernando, x86, agraf, kvm-ppc,
	linux-kernel, linuxppc-dev, mingo, paulus, avi, hpa, tglx,
	Takuya Yoshikawa
In-Reply-To: <20100511034329.GB3458@amt.cnet>

(2010/05/11 12:43), Marcelo Tosatti wrote:
> On Tue, May 04, 2010 at 10:08:21PM +0900, Takuya Yoshikawa wrote:
>> +How to Get
>> +
>> +Before calling this, you have to set the slot member of kvm_user_dirty_log
>> +to indicate the target memory slot.
>> +
>> +struct kvm_user_dirty_log {
>> +	__u32 slot;
>> +	__u32 flags;
>> +	__u64 dirty_bitmap;
>> +	__u64 dirty_bitmap_old;
>> +};
>> +
>> +The addresses will be set in the paired members: dirty_bitmap and _old.
>
> Why not pass the bitmap address to the kernel, instead of having the
> kernel allocate it. Because apparently you plan to do that in a new
> generation anyway?

Yes, we want to make qemu allocate and free bitmaps in the future.
But currently, those are strictly tied with memory slot registration and
changing it in one patch set is really difficult.

Anyway, we need kernel side allocation mechanism to keep the current
GET_DIRTY_LOG api. I don't mind not exporting kernel allocated bitmaps
in this patch set and later introducing a bitmap registration mechanism
in another patch set.

As this RFC is suggesting, kernel side double buffering infrastructure is
designed as general as possible and adding a new API like SWITCH can be done
naturally.

>
> Also, why does the kernel need to know about different bitmaps?

Because we need to support current GET API. We don't have any way to get
a new bitmap in the case of GET and we don't want to do_mmap() every time
for GET.

>
> One alternative would be:
>
> KVM_SWITCH_DIRTY_LOG passing the address of a bitmap. If the active
> bitmap was clean, it returns 0, no switch performed. If the active
> bitmap was dirty, the kernel switches to the new bitmap and returns 1.
>
> And the responsability of cleaning the new bitmap could also be left
> for userspace.
>

That is a beautiful approach but we can do that only when we give up using
GET api.


I follow you and Avi's advice about that kind of maintenance policy!
What do you think?

^ permalink raw reply

* [PATCH 1/2] powerpc: Add hcall to read 4 ptes at a time in real mode
From: Michael Neuling @ 2010-05-11  6:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, kexec, Anton Blanchard

This adds plpar_pte_read_4_raw() which can be used read 4 PTEs from
PHYP at a time, while in real mode.

It also creates a new hcall9 which can be used in real mode.  It's the
same as plpar_hcall9 but minus the tracing hcall statistics which may
require variables outside the RMO.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---

 arch/powerpc/include/asm/hvcall.h               |    1 
 arch/powerpc/platforms/pseries/hvCall.S         |   38 ++++++++++++++++++++++++
 arch/powerpc/platforms/pseries/plpar_wrappers.h |   18 +++++++++++
 3 files changed, 57 insertions(+)

Index: linux-2.6-ozlabs/arch/powerpc/include/asm/hvcall.h
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/include/asm/hvcall.h
+++ linux-2.6-ozlabs/arch/powerpc/include/asm/hvcall.h
@@ -281,6 +281,7 @@ long plpar_hcall_raw(unsigned long opcod
  */
 #define PLPAR_HCALL9_BUFSIZE 9
 long plpar_hcall9(unsigned long opcode, unsigned long *retbuf, ...);
+long plpar_hcall9_raw(unsigned long opcode, unsigned long *retbuf, ...);
 
 /* For hcall instrumentation.  One structure per-hcall, per-CPU */
 struct hcall_stats {
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hvCall.S
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/hvCall.S
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hvCall.S
@@ -228,3 +228,41 @@ _GLOBAL(plpar_hcall9)
 	mtcrf	0xff,r0
 
 	blr				/* return r3 = status */
+
+/* See plpar_hcall_raw to see why this is needed */
+_GLOBAL(plpar_hcall9_raw)
+	HMT_MEDIUM
+
+	mfcr	r0
+	stw	r0,8(r1)
+
+	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
+
+	mr	r4,r5
+	mr	r5,r6
+	mr	r6,r7
+	mr	r7,r8
+	mr	r8,r9
+	mr	r9,r10
+	ld	r10,STK_PARM(r11)(r1)	 /* put arg7 in R10 */
+	ld	r11,STK_PARM(r12)(r1)	 /* put arg8 in R11 */
+	ld	r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
+
+	HVSC				/* invoke the hypervisor */
+
+	mr	r0,r12
+	ld	r12,STK_PARM(r4)(r1)
+	std	r4,  0(r12)
+	std	r5,  8(r12)
+	std	r6, 16(r12)
+	std	r7, 24(r12)
+	std	r8, 32(r12)
+	std	r9, 40(r12)
+	std	r10,48(r12)
+	std	r11,56(r12)
+	std	r0, 64(r12)
+
+	lwz	r0,8(r1)
+	mtcrf	0xff,r0
+
+	blr				/* return r3 = status */
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/plpar_wrappers.h
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -191,6 +191,24 @@ static inline long plpar_pte_read_raw(un
 	return rc;
 }
 
+/*
+ * plpar_pte_read_4_raw can be called in real mode.
+ * ptes must be 8*sizeof(unsigned long)
+ */
+static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
+					unsigned long *ptes)
+
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+	rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
+
+	memcpy(ptes, retbuf, 8*sizeof(unsigned long));
+
+	return rc;
+}
+
 static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
 		unsigned long avpn)
 {

^ permalink raw reply

* [PATCH 2/2] powerpc,kexec: Speedup kexec hpte tear down
From: Michael Neuling @ 2010-05-11  6:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, kexec, Anton Blanchard
In-Reply-To: <1273559306.849145.937766276201.qpush@pale>

Currently for kexec the PTE tear down on 1TB segment systems normally
requires 3 hcalls for each PTE removal. On a machine with 32GB of
memory it can take around a minute to remove all the PTEs.

This optimises the path so that we only remove PTEs that are valid.
It also uses the read 4 PTEs at once HCALL.  For the common case where
a PTEs is invalid in a 1TB segment, this turns the 3 HCALLs per PTE
down to 1 HCALL per 4 PTEs.

This gives an > 10x speedup in kexec times on PHYP, taking a 32GB
machine from around 1 minute down to a few seconds.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---

 arch/powerpc/platforms/pseries/lpar.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)

Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/lpar.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
@@ -367,21 +367,28 @@ static void pSeries_lpar_hptab_clear(voi
 {
 	unsigned long size_bytes = 1UL << ppc64_pft_size;
 	unsigned long hpte_count = size_bytes >> 4;
-	unsigned long dummy1, dummy2, dword0;
+	struct {
+		unsigned long pteh;
+		unsigned long ptel;
+	} ptes[4];
 	long lpar_rc;
-	int i;
+	int i, j;
 
-	/* TODO: Use bulk call */
-	for (i = 0; i < hpte_count; i++) {
-		/* dont remove HPTEs with VRMA mappings */
-		lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG,
-						&dummy1, &dummy2);
-		if (lpar_rc == H_NOT_FOUND) {
-			lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1);
-			if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK)
-				!= HPTE_V_VRMA_MASK))
-				/* Can be hpte for 1TB Seg. So remove it */
-				plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2);
+	/* Read in batches of 4,
+	 * invalidate only valid entries not in the VRMA
+	 * hpte_count will be a multiple of 4
+         */
+	for (i = 0; i < hpte_count; i += 4) {
+		lpar_rc = plpar_pte_read_4_raw(0, i, (void *)ptes);
+		if (lpar_rc != H_SUCCESS)
+			continue;
+		for (j = 0; j < 4; j++){
+			if ((ptes[j].pteh & HPTE_V_VRMA_MASK) ==
+				HPTE_V_VRMA_MASK)
+				continue;
+			if (ptes[j].pteh & HPTE_V_VALID)
+				plpar_pte_remove_raw(0, i + j, 0,
+					&(ptes[j].pteh), &(ptes[j].ptel));
 		}
 	}
 }

^ permalink raw reply

* [PATCH] powerpc, kexec: Fix race in kexec shutdown
From: Michael Neuling @ 2010-05-11  6:28 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, kexec, Anton Blanchard

In kexec_prepare_cpus cpu, the primary CPU IPIs the secondary CPUs to
kexec_smp_down().  kexec_smp_down() calls kexec_smp_wait() which sets
the hw_cpu_id() to -1.  The primary does this while leaving IRQs on
which means the primary can take a timer interrupt which can lead to
the primary IPIing one of the secondary CPUs (say, for a scheduler
re-balance) but since the secondary CPU now has a hw_cpu_id = -1, we
IPI CPU -1... Kaboom!

We are hitting this case regularly on POWER7 machines.  

Also, the secondaries are clearing out any pending IPIs before
guaranteeing that no more will be received.  

This changes kexec_prepare_cpus() so that we turn off IRQs in the
primary CPU much earlier.  It adds a paca flag to say that the
secondaries have entered the kexec_smp_down() IPI and turned off IRQs,
rather than overloading hw_cpu_id with -1.

It also ensures that all CPUs have their IRQs off before we clear out
any pending IPI requests (in kexec_cpu_down()) to ensure there are no
trailing IPIs left unacknowledged.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---

 arch/powerpc/include/asm/paca.h        |    1 +
 arch/powerpc/kernel/machine_kexec_64.c |   28 ++++++++++++++++++++--------
 arch/powerpc/kernel/misc_64.S          |    3 ---
 3 files changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6-ozlabs/arch/powerpc/include/asm/paca.h
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/include/asm/paca.h
+++ linux-2.6-ozlabs/arch/powerpc/include/asm/paca.h
@@ -82,6 +82,7 @@ struct paca_struct {
 	s16 hw_cpu_id;			/* Physical processor number */
 	u8 cpu_start;			/* At startup, processor spins until */
 					/* this becomes non-zero. */
+	u8 kexec_irqs_off;		/* set when kexec down has irqs off */
 #ifdef CONFIG_PPC_STD_MMU_64
 	struct slb_shadow *slb_shadow_ptr;
 
Index: linux-2.6-ozlabs/arch/powerpc/kernel/machine_kexec_64.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/kernel/machine_kexec_64.c
+++ linux-2.6-ozlabs/arch/powerpc/kernel/machine_kexec_64.c
@@ -155,16 +155,23 @@ void kexec_copy_flush(struct kimage *ima
 
 #ifdef CONFIG_SMP
 
-/* FIXME: we should schedule this function to be called on all cpus based
- * on calling the interrupts, but we would like to call it off irq level
- * so that the interrupt controller is clean.
- */
+static int kexec_all_irq_disabled = 0;
+
 static void kexec_smp_down(void *arg)
 {
+	local_irq_disable();
+	mb(); /* make sure our irqs are disabled before we say they are */
+	get_paca()->kexec_irqs_off = 1;
+	while(kexec_all_irq_disabled == 0)
+		cpu_relax();
+	mb(); /* make sure all irqs are disabled before this */
+	/*
+	 * Now every CPU has IRQs off, we can clear out any pending
+	 * IPIs and be sure that no more will come in after this.
+	 */
 	if (ppc_md.kexec_cpu_down)
 		ppc_md.kexec_cpu_down(0, 1);
 
-	local_irq_disable();
 	kexec_smp_wait();
 	/* NOTREACHED */
 }
@@ -174,14 +181,17 @@ static void kexec_prepare_cpus(void)
 	int my_cpu, i, notified=-1;
 
 	smp_call_function(kexec_smp_down, NULL, /* wait */0);
+	local_irq_disable();
+	mb(); /* make sure IRQs are disabled before we say they are */
+	get_paca()->kexec_irqs_off = 1;
 	my_cpu = get_cpu();
 
-	/* check the others cpus are now down (via paca hw cpu id == -1) */
+	/* check the others cpus are now down (via paca kexec_irqs_off == 1) */
 	for (i=0; i < NR_CPUS; i++) {
 		if (i == my_cpu)
 			continue;
 
-		while (paca[i].hw_cpu_id != -1) {
+		while (paca[i].kexec_irqs_off != 1) {
 			barrier();
 			if (!cpu_possible(i)) {
 				printk("kexec: cpu %d hw_cpu_id %d is not"
@@ -207,6 +217,9 @@ static void kexec_prepare_cpus(void)
 			}
 		}
 	}
+	mb();
+	/* we are sure every CPU has IRQs off at this point */
+	kexec_all_irq_disabled = 1;
 
 	/* after we tell the others to go down */
 	if (ppc_md.kexec_cpu_down)
@@ -214,7 +227,6 @@ static void kexec_prepare_cpus(void)
 
 	put_cpu();
 
-	local_irq_disable();
 }
 
 #else /* ! SMP */
Index: linux-2.6-ozlabs/arch/powerpc/kernel/misc_64.S
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/kernel/misc_64.S
+++ linux-2.6-ozlabs/arch/powerpc/kernel/misc_64.S
@@ -494,14 +494,11 @@ kexec_flag:
  * note: this is a terminal routine, it does not save lr
  *
  * get phys id from paca
- * set paca id to -1 to say we got here
  * switch to real mode
  * join other cpus in kexec_wait(phys_id)
  */
 _GLOBAL(kexec_smp_wait)
 	lhz	r3,PACAHWCPUID(r13)
-	li	r4,-1
-	sth	r4,PACAHWCPUID(r13)	/* let others know we left */
 	bl	real_mode
 	b	.kexec_wait
 

^ permalink raw reply

* Re: [PATCH 2/2] powerpc,kexec: Speedup kexec hpte tear down
From: Michael Ellerman @ 2010-05-11  7:04 UTC (permalink / raw)
  To: Michael Neuling; +Cc: kexec, Anton Blanchard, linuxppc-dev
In-Reply-To: <20100511062826.E1C49D3340@localhost.localdomain>

[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]

On Tue, 2010-05-11 at 16:28 +1000, Michael Neuling wrote:
> Currently for kexec the PTE tear down on 1TB segment systems normally
> requires 3 hcalls for each PTE removal. On a machine with 32GB of
> memory it can take around a minute to remove all the PTEs.
> 
..
> -	/* TODO: Use bulk call */

...
> +	/* Read in batches of 4,
> +	 * invalidate only valid entries not in the VRMA
> +	 * hpte_count will be a multiple of 4
> +         */
> +	for (i = 0; i < hpte_count; i += 4) {
> +		lpar_rc = plpar_pte_read_4_raw(0, i, (void *)ptes);
> +		if (lpar_rc != H_SUCCESS)
> +			continue;
> +		for (j = 0; j < 4; j++){
> +			if ((ptes[j].pteh & HPTE_V_VRMA_MASK) ==
> +				HPTE_V_VRMA_MASK)
> +				continue;
> +			if (ptes[j].pteh & HPTE_V_VALID)
> +				plpar_pte_remove_raw(0, i + j, 0,
> +					&(ptes[j].pteh), &(ptes[j].ptel));
>  		}

Have you tried using the bulk remove call, if none of the HPTEs are for
the VRMA? Rumour was it was slower/the-same, but that may have been
apocryphal.

cheers

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Curious serial slowdown
From: Guillaume Dargaud @ 2010-05-11  6:18 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

Hello all,
I'm looking for hints on a curious problem.
I have a working kernel on a custom embedded device and it works fine.
We came up with a variation of the device with a few hardware changes, one 
of them being the number of serial ports that goes from 4 to 2.

In order to save time I tried my current kernel. When I boot the custom 
bootlader behaves the same, then the kernel boot behaves the same, but then 
once usermode is reached (the message "init started: BusyBox..."), the new 
card console display crawls to a halt (about one character per second 
instead of 115000 bauds !!!). But the card goes at normal speed as an ssh 
connection shows.

So my question is: is it caused by the fact that there are 2 missing serial 
ports ? Will making a new kernel with the correct hardware definition solve 
it ?
-- 
Guillaume Dargaud
http://www.gdargaud.net/ 

[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 3562 bytes --]

^ permalink raw reply

* [PATCH] kexec-tools, ppc64: Fix segfault parsing DR memory property
From: Matt Evans @ 2010-05-11  8:07 UTC (permalink / raw)
  To: kexec; +Cc: linuxppc-dev, horms


add_dyn_reconf_usable_mem_property() iterates over memory spans
in /ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory and intersects
these with usablemem_rgns ranges.  Not only did it seem to write
null properties for every range that didn't match, but it used an unchecked
fixed-size array which will overrun on machines with lots of LMBs.

This patch stops add_dyn_reconf_usable_mem_property() from adding null ranges
to the linux,drconf-usable-memory property and removes its fixed-size array,
as well as the array in add_usable_mem_property, in lieu of malloc/realloc/free.

Signed-off-by: Matt Evans <matt@ozlabs.org>
---
 kexec/arch/ppc64/fs2dt.c |   66 +++++++++++++++++++++++++++++++++++++--------
 1 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/kexec/arch/ppc64/fs2dt.c b/kexec/arch/ppc64/fs2dt.c
index 762bf04..7470132 100644
--- a/kexec/arch/ppc64/fs2dt.c
+++ b/kexec/arch/ppc64/fs2dt.c
@@ -37,7 +37,7 @@
 #define NAMESPACE 16384		/* max bytes for property names */
 #define INIT_TREE_WORDS 65536	/* Initial num words for prop values */
 #define MEMRESERVE 256		/* max number of reserved memory blocks */
-#define MAX_MEMORY_RANGES 1024
+#define MEM_RANGE_CHUNK_SZ 2048 /* Initial num dwords for mem ranges */
 
 static char pathname[MAXPATH], *pathstart;
 static char propnames[NAMESPACE] = { 0 };
@@ -148,7 +148,8 @@ static void add_dyn_reconf_usable_mem_property(int fd)
 {
 	char fname[MAXPATH], *bname;
 	uint64_t buf[32];
-	uint64_t ranges[2*MAX_MEMORY_RANGES];
+	uint64_t *ranges;
+	int ranges_size = MEM_RANGE_CHUNK_SZ;
 	uint64_t base, end, loc_base, loc_end;
 	size_t i, rngs_cnt, range;
 	int rlen = 0;
@@ -165,6 +166,11 @@ static void add_dyn_reconf_usable_mem_property(int fd)
 		die("unrecoverable error: error seeking in \"%s\": %s\n",
 			pathname, strerror(errno));
 
+	ranges = malloc(ranges_size*8);
+	if (!ranges)
+		die("unrecoverable error: can't alloc %d bytes for ranges.\n",
+		    ranges_size*8);
+
 	rlen = 0;
 	for (i = 0; i < num_of_lmbs; i++) {
 		if (read(fd, buf, 24) < 0)
@@ -180,24 +186,41 @@ static void add_dyn_reconf_usable_mem_property(int fd)
 
 		rngs_cnt = 0;
 		for (range = 0; range < usablemem_rgns.size; range++) {
+			int add = 0;
 			loc_base = usablemem_rgns.ranges[range].start;
 			loc_end = usablemem_rgns.ranges[range].end;
 			if (loc_base >= base && loc_end <= end) {
-				ranges[rlen++] = loc_base;
-				ranges[rlen++] = loc_end - loc_base;
-				rngs_cnt++;
+				add = 1;
 			} else if (base < loc_end && end > loc_base) {
 				if (loc_base < base)
 					loc_base = base;
 				if (loc_end > end)
 					loc_end = end;
+				add = 1;
+			}
+
+			if (add) {
+				if (rlen >= (ranges_size-2)) {
+					ranges_size += MEM_RANGE_CHUNK_SZ;
+					ranges = realloc(ranges, ranges_size*8);
+					if (!ranges)
+						die("unrecoverable error: can't"
+						    " realloc %d bytes for"
+						    " ranges.\n",
+						    ranges_size*8);
+				}
 				ranges[rlen++] = loc_base;
 				ranges[rlen++] = loc_end - loc_base;
 				rngs_cnt++;
 			}
 		}
-		/* Store the count of (base, size) duple */
-		ranges[tmp_indx] = rngs_cnt;
+		if (rngs_cnt == 0) {
+			/* Don't store anything for unwritten iterations! */
+			rlen = tmp_indx;
+		} else {
+			/* Store the count of (base, size) duple */
+			ranges[tmp_indx] = rngs_cnt;
+		}
 	}
 		
 	rlen = rlen * sizeof(uint64_t);
@@ -210,7 +233,8 @@ static void add_dyn_reconf_usable_mem_property(int fd)
 	*dt++ = propnum("linux,drconf-usable-memory");
 	if ((rlen >= 8) && ((unsigned long)dt & 0x4))
 		dt++;
-	memcpy(dt, &ranges, rlen);
+	memcpy(dt, ranges, rlen);
+	free(ranges);
 	dt += (rlen + 3)/4;
 }
 
@@ -218,7 +242,8 @@ static void add_usable_mem_property(int fd, size_t len)
 {
 	char fname[MAXPATH], *bname;
 	uint64_t buf[2];
-	uint64_t ranges[2*MAX_MEMORY_RANGES];
+	uint64_t *ranges;
+	int ranges_size = MEM_RANGE_CHUNK_SZ;
 	uint64_t base, end, loc_base, loc_end;
 	size_t range;
 	int rlen = 0;
@@ -247,17 +272,33 @@ static void add_usable_mem_property(int fd, size_t len)
 	base = buf[0];
 	end = base + buf[1];
 
+	ranges = malloc(ranges_size*8);
+	if (!ranges)
+		die("unrecoverable error: can't alloc %d bytes for ranges.\n",
+		    ranges_size*8);
+
 	for (range = 0; range < usablemem_rgns.size; range++) {
+		int add = 0;
 		loc_base = usablemem_rgns.ranges[range].start;
 		loc_end = usablemem_rgns.ranges[range].end;
 		if (loc_base >= base && loc_end <= end) {
-			ranges[rlen++] = loc_base;
-			ranges[rlen++] = loc_end - loc_base;
+			add = 1;
 		} else if (base < loc_end && end > loc_base) {
 			if (loc_base < base)
 				loc_base = base;
 			if (loc_end > end)
 				loc_end = end;
+			add = 1;
+		}
+		if (add) {
+			if (rlen >= (ranges_size-2)) {
+				ranges_size += MEM_RANGE_CHUNK_SZ;
+				ranges = realloc(ranges, ranges_size*8);
+				if (!ranges) 
+					die("unrecoverable error: can't realloc"
+					    "%d bytes for ranges.\n",
+					    ranges_size*8);
+			}
 			ranges[rlen++] = loc_base;
 			ranges[rlen++] = loc_end - loc_base;
 		}
@@ -283,7 +324,8 @@ static void add_usable_mem_property(int fd, size_t len)
 	*dt++ = propnum("linux,usable-memory");
 	if ((rlen >= 8) && ((unsigned long)dt & 0x4))
 		dt++;
-	memcpy(dt,&ranges,rlen);
+	memcpy(dt, ranges, rlen);
+	free(ranges);
 	dt += (rlen + 3)/4;
 }
 
-- 
1.6.3.3

^ permalink raw reply related

* Re: [RFC][PATCH 0/12] KVM, x86, ppc, asm-generic: moving dirty bitmaps to user space
From: Takuya Yoshikawa @ 2010-05-11 10:11 UTC (permalink / raw)
  To: Avi Kivity
  Cc: linux-arch, x86, arnd, kvm, kvm-ia64, fernando, mtosatti, agraf,
	kvm-ppc, linux-kernel, linuxppc-dev, mingo, paulus, hpa, tglx,
	Takuya Yoshikawa
In-Reply-To: <4BE7FB7B.5010600@oss.ntt.co.jp>


>>>
>>> In usual workload, the number of dirty pages varies a lot for each
>>> iteration
>>> and we should gain really a lot for relatively clean cases.
>>
>> Can you post such a test, for an idle large guest?
>
> OK, I'll do!


Result of "low workload test" (running top during migration) first,

4GB guest
picked up slots[1](len=3757047808) only
*****************************************
     get.org     get.opt    switch.opt

     1060875     310292     190335
     1076754     301295     188600
      655504     318284     196029
      529769     301471        325
      694796      70216     221172
      651868     353073     196184
      543339     312865     213236
     1061938      72785     203090
      689527     323901     249519
      621364     323881        473
     1063671      70703     192958
      915903     336318     174008
     1046462     332384        782
     1037942      72783     190655
      680122     318305     243544
      688156     314935     193526
      558658     265934     190550
      652454     372135     196270
      660140      68613        352
     1101947     378642     186575
         ...        ...        ...
*****************************************

As expected we've got the difference more clearly.

In this case, switch.opt reduced 1/3 (.1 msec) compared to get.opt
for each iteration.

And when the slot is cleaner, the ratio is bigger.




>
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] 85xx: Fix PCI-E interrupt mapping for slot 0 of P2020DS
From: Kumar Gala @ 2010-05-11 12:35 UTC (permalink / raw)
  To: Felix Radensky; +Cc: linuxppc-dev
In-Reply-To: <1273518917-10229-1-git-send-email-felix@embedded-sol.com>

[-- Attachment #1: Type: text/html, Size: 5233 bytes --]

^ permalink raw reply

* Re: [PATCH] 85xx: Fix PCI-E interrupt mapping for slot 0 of P2020DS
From: Kumar Gala @ 2010-05-11 12:36 UTC (permalink / raw)
  To: Felix Radensky; +Cc: linuxppc-dev
In-Reply-To: <1273518917-10229-1-git-send-email-felix@embedded-sol.com>


On May 10, 2010, at 2:15 PM, Felix Radensky wrote:

> Fix legacy PCI-E interrupt mapping for PCI-E slot 0 of
> P2020DS evaluation board. The patch is based on P2020DS
> device tree from Freescale BSP for this board.
>=20
> Signed-off-by: Felix Radensky <felix@embedded-sol.com>
> ---
> arch/powerpc/boot/dts/p2020ds.dts |    8 ++++----
> 1 files changed, 4 insertions(+), 4 deletions(-)

I don't understand why this is needed?

-k

>=20
> diff --git a/arch/powerpc/boot/dts/p2020ds.dts =
b/arch/powerpc/boot/dts/p2020ds.dts
> index 1101914..7c5fc07 100644
> --- a/arch/powerpc/boot/dts/p2020ds.dts
> +++ b/arch/powerpc/boot/dts/p2020ds.dts
> @@ -507,10 +507,10 @@
> 		interrupt-map-mask =3D <0xf800 0x0 0x0 0x7>;
> 		interrupt-map =3D <
> 			/* IDSEL 0x0 */
> -			0000 0x0 0x0 0x1 &mpic 0x8 0x1
> -			0000 0x0 0x0 0x2 &mpic 0x9 0x1
> -			0000 0x0 0x0 0x3 &mpic 0xa 0x1
> -			0000 0x0 0x0 0x4 &mpic 0xb 0x1
> +			0000 0x0 0x0 0x1 &mpic 0x8 0x2
> +			0000 0x0 0x0 0x2 &mpic 0x9 0x2
> +			0000 0x0 0x0 0x3 &mpic 0xa 0x2
> +			0000 0x0 0x0 0x4 &mpic 0xb 0x2
> 			>;
> 		pcie@0 {
> 			reg =3D <0x0 0x0 0x0 0x0 0x0>;
> --=20
> 1.5.4.3

^ permalink raw reply

* Re: [PATCH] powerpc: Use more accurate limit for first segment memory allocations
From: Michael Ellerman @ 2010-05-11 13:24 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, miltonm, linuxppc-dev
In-Reply-To: <20100511045918.GA13509@kryten>

[-- Attachment #1: Type: text/plain, Size: 1499 bytes --]

On Tue, 2010-05-11 at 14:59 +1000, Anton Blanchard wrote:
> Author: Milton Miller <miltonm@bga.com>
> 
> On large machines we are running out of room below 256MB. In some cases we
> only need to ensure the allocation is in the first segment, which may be
> 256MB or 1TB.
> 
> Add slb0_limit and use it to specify the upper limit for the irqstack and
> emergency stacks.
> 
> On a large ppc64 box, this fixes a panic at boot when the crashkernel=
> option is specified (previously we would run out of memory below 256MB).
> 
> Signed-off-by: Milton Miller <miltonm@bga.com>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> 
> Some things we should add:
> 
> - Specify a more intelligent limit for BookE
> - The allocation of the PACAs should use this limit too

We access the PACA from real mode?

> Index: linux-2.6/arch/powerpc/kernel/setup_64.c
> ===================================================================
> --- linux-2.6.orig/arch/powerpc/kernel/setup_64.c	2010-04-22 17:23:42.000000000 +1000
> +++ linux-2.6/arch/powerpc/kernel/setup_64.c	2010-04-30 09:46:15.000000000 +1000
> @@ -424,9 +424,18 @@ void __init setup_system(void)
>  	DBG(" <- setup_system()\n");
>  }
>  
> +static u64 slb0_limit(void)
> +{
> +	if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
> +		return 1UL << SID_SHIFT_1T;
> +	}
> +	return 1UL << SID_SHIFT;
> +}

I take it there's no chance the CPU feature is there but we're using 256
for whatever reason?

cheers


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* [PATCH] powerpc/44x: Add basic ICON PPC440SPe board support
From: Stefan Roese @ 2010-05-11 13:55 UTC (permalink / raw)
  To: linuxppc-dev

ICON is based on the AppliedMicro 440SPe. It is equipped with
64MByte NOR FLASH, SODIMM, Gigabit ethernet, SM502 on PCI(X),
LSI SAS1068E on PCIe0 and custom FPGA on PCIe1.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Josh Boyer <jwboyer@linux.vnet.ibm.com>
---
 arch/powerpc/boot/dts/icon.dts             |  447 ++++++++++
 arch/powerpc/configs/44x/icon_defconfig    | 1316 ++++++++++++++++++++++++++++
 arch/powerpc/platforms/44x/Kconfig         |   11 +
 arch/powerpc/platforms/44x/ppc44x_simple.c |    3 +-
 4 files changed, 1776 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/icon.dts
 create mode 100644 arch/powerpc/configs/44x/icon_defconfig

diff --git a/arch/powerpc/boot/dts/icon.dts b/arch/powerpc/boot/dts/icon.dts
new file mode 100644
index 0000000..abcd0ca
--- /dev/null
+++ b/arch/powerpc/boot/dts/icon.dts
@@ -0,0 +1,447 @@
+/*
+ * Device Tree Source for Mosaix Technologies, Inc. ICON board
+ *
+ * Copyright 2010 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <2>;
+	model = "mosaixtech,icon";
+	compatible = "mosaixtech,icon";
+	dcr-parent = <&{/cpus/cpu@0}>;
+
+	aliases {
+		ethernet0 = &EMAC0;
+		serial0 = &UART0;
+		serial1 = &UART1;
+		serial2 = &UART2;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			model = "PowerPC,440SPe";
+			reg = <0x00000000>;
+			clock-frequency = <0>; /* Filled in by U-Boot */
+			timebase-frequency = <0>; /* Filled in by U-Boot */
+			i-cache-line-size = <32>;
+			d-cache-line-size = <32>;
+			i-cache-size = <32768>;
+			d-cache-size = <32768>;
+			dcr-controller;
+			dcr-access-method = "native";
+			reset-type = <2>;	/* Use chip-reset */
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x00000000>; /* Filled in by U-Boot */
+	};
+
+	UIC0: interrupt-controller0 {
+		compatible = "ibm,uic-440spe","ibm,uic";
+		interrupt-controller;
+		cell-index = <0>;
+		dcr-reg = <0x0c0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+	};
+
+	UIC1: interrupt-controller1 {
+		compatible = "ibm,uic-440spe","ibm,uic";
+		interrupt-controller;
+		cell-index = <1>;
+		dcr-reg = <0x0d0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	UIC2: interrupt-controller2 {
+		compatible = "ibm,uic-440spe","ibm,uic";
+		interrupt-controller;
+		cell-index = <2>;
+		dcr-reg = <0x0e0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	UIC3: interrupt-controller3 {
+		compatible = "ibm,uic-440spe","ibm,uic";
+		interrupt-controller;
+		cell-index = <3>;
+		dcr-reg = <0x0f0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	SDR0: sdr {
+		compatible = "ibm,sdr-440spe";
+		dcr-reg = <0x00e 0x002>;
+	};
+
+	CPR0: cpr {
+		compatible = "ibm,cpr-440spe";
+		dcr-reg = <0x00c 0x002>;
+	};
+
+	MQ0: mq {
+		compatible = "ibm,mq-440spe";
+		dcr-reg = <0x040 0x020>;
+	};
+
+	plb {
+		compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		/*        addr-child     addr-parent    size */
+		ranges = <0x4 0x00100000 0x4 0x00100000 0x00001000
+			  0x4 0x00200000 0x4 0x00200000 0x00000400
+			  0x4 0xe0000000 0x4 0xe0000000 0x20000000
+			  0xc 0x00000000 0xc 0x00000000 0x20000000
+			  0xd 0x00000000 0xd 0x00000000 0x80000000
+			  0xd 0x80000000 0xd 0x80000000 0x80000000
+			  0xe 0x00000000 0xe 0x00000000 0x80000000
+			  0xe 0x80000000 0xe 0x80000000 0x80000000
+			  0xf 0x00000000 0xf 0x00000000 0x80000000
+			  0xf 0x80000000 0xf 0x80000000 0x80000000>;
+		clock-frequency = <0>; /* Filled in by U-Boot */
+
+		SDRAM0: sdram {
+			compatible = "ibm,sdram-440spe", "ibm,sdram-405gp";
+			dcr-reg = <0x010 0x002>;
+		};
+
+		MAL0: mcmal {
+			compatible = "ibm,mcmal-440spe", "ibm,mcmal2";
+			dcr-reg = <0x180 0x062>;
+			num-tx-chans = <2>;
+			num-rx-chans = <1>;
+			interrupt-parent = <&MAL0>;
+			interrupts = <0x0 0x1 0x2 0x3 0x4>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-map = </*TXEOB*/ 0x0 &UIC1 0x6 0x4
+					 /*RXEOB*/ 0x1 &UIC1 0x7 0x4
+					 /*SERR*/  0x2 &UIC1 0x1 0x4
+					 /*TXDE*/  0x3 &UIC1 0x2 0x4
+					 /*RXDE*/  0x4 &UIC1 0x3 0x4>;
+		};
+
+		POB0: opb {
+			compatible = "ibm,opb-440spe", "ibm,opb-440gp", "ibm,opb";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0xe0000000 0x00000004 0xe0000000 0x20000000>;
+			clock-frequency = <0>; /* Filled in by U-Boot */
+
+			EBC0: ebc {
+				compatible = "ibm,ebc-440spe", "ibm,ebc-440gp", "ibm,ebc";
+				dcr-reg = <0x012 0x002>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				clock-frequency = <0>; /* Filled in by U-Boot */
+				/* ranges property is supplied by U-Boot */
+				interrupts = <0x5 0x1>;
+				interrupt-parent = <&UIC1>;
+
+				nor_flash@0,0 {
+					compatible = "cfi-flash";
+					bank-width = <2>;
+					reg = <0x00000000 0x00000000 0x01000000>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					partition@0 {
+						label = "kernel";
+						reg = <0x00000000 0x001e0000>;
+					};
+					partition@1e0000 {
+						label = "dtb";
+						reg = <0x001e0000 0x00020000>;
+					};
+					partition@200000 {
+						label = "root";
+						reg = <0x00200000 0x00200000>;
+					};
+					partition@400000 {
+						label = "user";
+						reg = <0x00400000 0x00b60000>;
+					};
+					partition@f60000 {
+						label = "env";
+						reg = <0x00f60000 0x00040000>;
+					};
+					partition@fa0000 {
+						label = "u-boot";
+						reg = <0x00fa0000 0x00060000>;
+					};
+				};
+
+				SysACE_CompactFlash: sysace@1,0 {
+					compatible = "xlnx,sysace";
+					interrupt-parent = <&UIC2>;
+					interrupts = <24 0x4>;
+					reg = <0x00000001 0x00000000 0x10000>;
+				};
+			};
+
+			UART0: serial@f0000200 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <0xf0000200 0x00000008>;
+				virtual-reg = <0xa0000200>;
+				clock-frequency = <0>; /* Filled in by U-Boot */
+				current-speed = <115200>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x0 0x4>;
+			};
+
+			UART1: serial@f0000300 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <0xf0000300 0x00000008>;
+				virtual-reg = <0xa0000300>;
+				clock-frequency = <0>;
+				current-speed = <0>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x1 0x4>;
+			};
+
+
+			UART2: serial@f0000600 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <0xf0000600 0x00000008>;
+				virtual-reg = <0xa0000600>;
+				clock-frequency = <0>;
+				current-speed = <0>;
+				interrupt-parent = <&UIC1>;
+				interrupts = <0x5 0x4>;
+			};
+
+			IIC0: i2c@f0000400 {
+				compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic";
+				reg = <0xf0000400 0x00000014>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x2 0x4>;
+			};
+
+			IIC1: i2c@f0000500 {
+				compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic";
+				reg = <0xf0000500 0x00000014>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x3 0x4>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+                                rtc@68 {
+                                        compatible = "stm,m41t00";
+                                        reg = <0x68>;
+                                };
+			};
+
+			EMAC0: ethernet@f0000800 {
+				linux,network-index = <0x0>;
+				device_type = "network";
+				compatible = "ibm,emac-440spe", "ibm,emac4";
+				interrupt-parent = <&UIC1>;
+				interrupts = <0x1c 0x4 0x1d 0x4>;
+				reg = <0xf0000800 0x00000074>;
+				local-mac-address = [000000000000];
+				mal-device = <&MAL0>;
+				mal-tx-channel = <0>;
+				mal-rx-channel = <0>;
+				cell-index = <0>;
+				max-frame-size = <9000>;
+				rx-fifo-size = <4096>;
+				tx-fifo-size = <2048>;
+				phy-mode = "gmii";
+				phy-map = <0x00000000>;
+				has-inverted-stacr-oc;
+				has-new-stacr-staopc;
+			};
+		};
+
+		PCIX0: pci@c0ec00000 {
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "ibm,plb-pcix-440spe", "ibm,plb-pcix";
+			primary;
+			large-inbound-windows;
+			enable-msi-hole;
+			reg = <0x0000000c 0x0ec00000 0x00000008   /* Config space access */
+			       0x00000000 0x00000000 0x00000000   /* no IACK cycles */
+			       0x0000000c 0x0ed00000 0x00000004   /* Special cycles */
+			       0x0000000c 0x0ec80000 0x00000100   /* Internal registers */
+			       0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */
+
+			/* Outbound ranges, one memory and one IO,
+			 * later cannot be changed
+			 */
+			ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
+				  0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
+
+			/* Inbound 4GB range starting at 0 */
+			dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+			/* This drives busses 0 to 0xf */
+			bus-range = <0x0 0xf>;
+
+			/* PCI-X interrupt (SM502) is routed to extIRQ10 (UIC1, 19) */
+			interrupt-map-mask = <0x0 0x0 0x0 0x0>;
+			interrupt-map = <0x0 0x0 0x0 0x0 &UIC1 19 0x8>;
+		};
+
+		PCIE0: pciex@d00000000 {
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
+			primary;
+			port = <0x0>; /* port number */
+			reg = <0x0000000d 0x00000000 0x20000000	/* Config space access */
+			       0x0000000c 0x10000000 0x00001000>;	/* Registers */
+			dcr-reg = <0x100 0x020>;
+			sdr-base = <0x300>;
+
+			/* Outbound ranges, one memory and one IO,
+			 * later cannot be changed
+			 */
+			ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+				  0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+			/* Inbound 4GB range starting at 0 */
+			dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+			/* This drives busses 0x10 to 0x1f */
+			bus-range = <0x10 0x1f>;
+
+			/* Legacy interrupts (note the weird polarity, the bridge seems
+			 * to invert PCIe legacy interrupts).
+			 * We are de-swizzling here because the numbers are actually for
+			 * port of the root complex virtual P2P bridge. But I want
+			 * to avoid putting a node for it in the tree, so the numbers
+			 * below are basically de-swizzled numbers.
+			 * The real slot is on idsel 0, so the swizzling is 1:1
+			 */
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <
+				0x0 0x0 0x0 0x1 &UIC3 0x0 0x4 /* swizzled int A */
+				0x0 0x0 0x0 0x2 &UIC3 0x1 0x4 /* swizzled int B */
+				0x0 0x0 0x0 0x3 &UIC3 0x2 0x4 /* swizzled int C */
+				0x0 0x0 0x0 0x4 &UIC3 0x3 0x4 /* swizzled int D */>;
+		};
+
+		PCIE1: pciex@d20000000 {
+			device_type = "pci";
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
+			primary;
+			port = <0x1>; /* port number */
+			reg = <0x0000000d 0x20000000 0x20000000	/* Config space access */
+			       0x0000000c 0x10001000 0x00001000>;	/* Registers */
+			dcr-reg = <0x120 0x020>;
+			sdr-base = <0x340>;
+
+			/* Outbound ranges, one memory and one IO,
+			 * later cannot be changed
+			 */
+			ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
+				  0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
+
+			/* Inbound 4GB range starting at 0 */
+			dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+			/* This drives busses 0x20 to 0x2f */
+			bus-range = <0x20 0x2f>;
+
+			/* Legacy interrupts (note the weird polarity, the bridge seems
+			 * to invert PCIe legacy interrupts).
+			 * We are de-swizzling here because the numbers are actually for
+			 * port of the root complex virtual P2P bridge. But I want
+			 * to avoid putting a node for it in the tree, so the numbers
+			 * below are basically de-swizzled numbers.
+			 * The real slot is on idsel 0, so the swizzling is 1:1
+			 */
+			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+			interrupt-map = <
+				0x0 0x0 0x0 0x1 &UIC3 0x4 0x4 /* swizzled int A */
+				0x0 0x0 0x0 0x2 &UIC3 0x5 0x4 /* swizzled int B */
+				0x0 0x0 0x0 0x3 &UIC3 0x6 0x4 /* swizzled int C */
+				0x0 0x0 0x0 0x4 &UIC3 0x7 0x4 /* swizzled int D */>;
+		};
+
+		I2O: i2o@400100000 {
+			compatible = "ibm,i2o-440spe";
+			reg = <0x00000004 0x00100000 0x100>;
+			dcr-reg = <0x060 0x020>;
+		};
+
+		DMA0: dma0@400100100 {
+			compatible = "ibm,dma-440spe";
+			cell-index = <0>;
+			reg = <0x00000004 0x00100100 0x100>;
+			dcr-reg = <0x060 0x020>;
+			interrupt-parent = <&DMA0>;
+			interrupts = <0 1>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-map = <
+				0 &UIC0 0x14 4
+				1 &UIC1 0x16 4>;
+		};
+
+		DMA1: dma1@400100200 {
+			compatible = "ibm,dma-440spe";
+			cell-index = <1>;
+			reg = <0x00000004 0x00100200 0x100>;
+			dcr-reg = <0x060 0x020>;
+			interrupt-parent = <&DMA1>;
+			interrupts = <0 1>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-map = <
+				0 &UIC0 0x16 4
+				1 &UIC1 0x16 4>;
+		};
+
+		xor-accel@400200000 {
+			compatible = "amcc,xor-accelerator";
+			reg = <0x00000004 0x00200000 0x400>;
+			interrupt-parent = <&UIC1>;
+			interrupts = <0x1f 4>;
+		};
+	};
+
+	chosen {
+		linux,stdout-path = "/plb/opb/serial@f0000200";
+	};
+};
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
new file mode 100644
index 0000000..40a755b
--- /dev/null
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -0,0 +1,1316 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.34-rc5
+# Mon Apr 26 16:44:40 2010
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_PPC_BOOK3S_32 is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MMU_NOHASH_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_NR_IRQS=512
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_PPC_ADV_DEBUG_REGS=y
+CONFIG_PPC_ADV_DEBUG_IACS=4
+CONFIG_PPC_ADV_DEBUG_DACS=2
+CONFIG_PPC_ADV_DEBUG_DVCS=2
+CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+# CONFIG_LOGBUFFER is not set
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+CONFIG_PPC4xx_PCI_EXPRESS=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
+# CONFIG_EBONY is not set
+# CONFIG_SAM440EP is not set
+# CONFIG_SEQUOIA is not set
+# CONFIG_TAISHAN is not set
+# CONFIG_KATMAI is not set
+# CONFIG_RAINIER is not set
+# CONFIG_WARP is not set
+# CONFIG_ARCHES is not set
+# CONFIG_CANYONLANDS is not set
+# CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_EIGER is not set
+# CONFIG_YOSEMITE is not set
+CONFIG_ICON=y
+# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
+CONFIG_PPC44x_SIMPLE=y
+# CONFIG_PPC4xx_GPIO is not set
+CONFIG_440SPe=y
+CONFIG_STDBINUTILS=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_MAX_ACTIVE_REGIONS=32
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_ARCH_HAS_NMI_WATCHDOG is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_4xx_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=35000
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_XILINX_SYSACE=y
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_FUSION=y
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+CONFIG_FUSION_SAS=y
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_CTL=y
+CONFIG_FUSION_LOGGING=y
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# The newer stack is recommended.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+CONFIG_IBM_NEW_EMAC_EMAC4=y
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_BOOTCOUNT is not set
+# CONFIG_DISPLAY_PDSP1880 is not set
+# CONFIG_MUCMC52_IO is not set
+# CONFIG_UC101_IO is not set
+# CONFIG_SRAM is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_PPC4XX is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 8764a13..4d5b299 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -151,6 +151,17 @@ config YOSEMITE
 	help
 	  This option enables support for the AMCC PPC440EP evaluation board.
 
+config ICON
+	bool "Icon"
+	depends on 44x
+	default n
+	select PPC44x_SIMPLE
+	select 440SPe
+	select PCI
+	select PPC4xx_PCI_EXPRESS
+	help
+	  This option enables support for the AMCC PPC440SPe evaluation board.
+
 #config LUAN
 #	bool "Luan"
 #	depends on 44x
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index e8c23cc..5f7a29d 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -61,7 +61,8 @@ static char *board[] __initdata = {
 	"amcc,redwood",
 	"amcc,sequoia",
 	"amcc,taishan",
-	"amcc,yosemite"
+	"amcc,yosemite",
+	"mosaixtech,icon"
 };
 
 static int __init ppc44x_probe(void)
-- 
1.7.1

^ permalink raw reply related

* Re: [RFC][PATCH 11/12] KVM: introduce new API for getting/switching dirty bitmaps
From: Marcelo Tosatti @ 2010-05-11 14:07 UTC (permalink / raw)
  To: Takuya Yoshikawa
  Cc: linux-arch, arnd, kvm, kvm-ia64, fernando, x86, agraf, kvm-ppc,
	linux-kernel, linuxppc-dev, mingo, paulus, avi, hpa, tglx,
	Takuya Yoshikawa
In-Reply-To: <4BE8F0F2.60706@oss.ntt.co.jp>

On Tue, May 11, 2010 at 02:53:54PM +0900, Takuya Yoshikawa wrote:
> (2010/05/11 12:43), Marcelo Tosatti wrote:
> >On Tue, May 04, 2010 at 10:08:21PM +0900, Takuya Yoshikawa wrote:
> >>+How to Get
> >>+
> >>+Before calling this, you have to set the slot member of kvm_user_dirty_log
> >>+to indicate the target memory slot.
> >>+
> >>+struct kvm_user_dirty_log {
> >>+	__u32 slot;
> >>+	__u32 flags;
> >>+	__u64 dirty_bitmap;
> >>+	__u64 dirty_bitmap_old;
> >>+};
> >>+
> >>+The addresses will be set in the paired members: dirty_bitmap and _old.
> >
> >Why not pass the bitmap address to the kernel, instead of having the
> >kernel allocate it. Because apparently you plan to do that in a new
> >generation anyway?
> 
> Yes, we want to make qemu allocate and free bitmaps in the future.
> But currently, those are strictly tied with memory slot registration and
> changing it in one patch set is really difficult.
> 
> Anyway, we need kernel side allocation mechanism to keep the current
> GET_DIRTY_LOG api. I don't mind not exporting kernel allocated bitmaps
> in this patch set and later introducing a bitmap registration mechanism
> in another patch set.
> 
> As this RFC is suggesting, kernel side double buffering infrastructure is
> designed as general as possible and adding a new API like SWITCH can be done
> naturally.
> 
> >
> >Also, why does the kernel need to know about different bitmaps?
> 
> Because we need to support current GET API. We don't have any way to get
> a new bitmap in the case of GET and we don't want to do_mmap() every time
> for GET.
> 
> >
> >One alternative would be:
> >
> >KVM_SWITCH_DIRTY_LOG passing the address of a bitmap. If the active
> >bitmap was clean, it returns 0, no switch performed. If the active
> >bitmap was dirty, the kernel switches to the new bitmap and returns 1.
> >
> >And the responsability of cleaning the new bitmap could also be left
> >for userspace.
> >
> 
> That is a beautiful approach but we can do that only when we give up using
> GET api.
> 
> 
> I follow you and Avi's advice about that kind of maintenance policy!
> What do you think?

If you introduce a switch ioctl that frees the bitmap vmalloc'ed by the
current set_memory_region (if its not freed already), after pointing the
memslot to the user supplied one, it should be fine?

^ permalink raw reply

* [PATCH] Fix kexec on powerpc32
From: Maxim Uvarov @ 2010-05-11 14:53 UTC (permalink / raw)
  To: linuxppc-dev, kexec, uvarov; +Cc: lists, horms


Hello everybody,

      Please find here patch for user land kexec-tools application. Following
      patch makes kexec-tools work for both kexec and kdump. I tested it with 
      git kernel (linus-tree) and Freescale/Logic MPC8360ERDK board with 
      mpc83xx_defconfig kernel config.

      kexec:
      kexec -l vmlinux --command-line="console= ... etc"
      kexec -e

      kdump:
      kexec -p vmlinux_dump --command-line="console=... etc"
      echo c > /proc/sysrq-trigger

      I also think that is is reasonable:
      - put GAME_CUBE specific code to separate files;
      - combine  ppc and ppc64 to powerpc directory (I'm planning to do it.
	And that why in some places my patch have ifdefs for PPC64);

Best regards,
Maxim Uvarov.

From: Maxim Uvarov <muvarov@gmail.com>

Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
---

 kexec/arch/ppc/Makefile            |    2 
 kexec/arch/ppc/crashdump-powerpc.c |  439 ++++++++++++++++++++++++++++++++++
 kexec/arch/ppc/crashdump-powerpc.h |   38 +++
 kexec/arch/ppc/fs2dt.c             |  460 ++++++++++++++++++++++++++++++++++++
 kexec/arch/ppc/kexec-elf-ppc.c     |  186 +++++++++++++--
 kexec/arch/ppc/kexec-ppc.c         |  276 ++++++++++++++++++++--
 kexec/arch/ppc/kexec-ppc.h         |   32 +++
 purgatory/arch/ppc/Makefile        |    2 
 purgatory/arch/ppc/purgatory-ppc.c |   38 ++-
 purgatory/arch/ppc/purgatory-ppc.h |    4 
 purgatory/arch/ppc/v2wrap.S        |   66 -----
 purgatory/arch/ppc/v2wrap_32.S     |   91 +++++++
 12 files changed, 1524 insertions(+), 110 deletions(-)
 create mode 100644 kexec/arch/ppc/crashdump-powerpc.c
 create mode 100644 kexec/arch/ppc/crashdump-powerpc.h
 create mode 100644 kexec/arch/ppc/fs2dt.c
 delete mode 100644 purgatory/arch/ppc/v2wrap.S
 create mode 100644 purgatory/arch/ppc/v2wrap_32.S

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 1c7441c..5988213 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -11,6 +11,8 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-uImage-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/fs2dt.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/crashdump-powerpc.c
 ppc_KEXEC_SRCS += kexec/kexec-uImage.c
 
 libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
diff --git a/kexec/arch/ppc/crashdump-powerpc.c b/kexec/arch/ppc/crashdump-powerpc.c
new file mode 100644
index 0000000..7bfad20
--- /dev/null
+++ b/kexec/arch/ppc/crashdump-powerpc.c
@@ -0,0 +1,439 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-ppc.h"
+#include "crashdump-powerpc.h"
+
+#ifdef CONFIG_PPC64
+static struct crash_elf_info elf_info64 = {
+class: ELFCLASS64,
+data: ELFDATA2MSB,
+machine: EM_PPC64,
+backup_src_start: BACKUP_SRC_START,
+backup_src_end: BACKUP_SRC_END,
+page_offset: PAGE_OFFSET,
+lowmem_limit: MAXMEM,
+};
+#endif
+static struct crash_elf_info elf_info32 = {
+class: ELFCLASS32,
+data: ELFDATA2MSB,
+#ifdef CONFIG_PPC64
+machine: EM_PPC64,
+#else
+machine: EM_PPC,
+#endif
+backup_src_start: BACKUP_SRC_START,
+backup_src_end: BACKUP_SRC_END,
+page_offset: PAGE_OFFSET,
+lowmem_limit: MAXMEM,
+};
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region
+ */
+static struct memory_range *crash_memory_range;
+
+/* Define a variable to replace the CRASH_MAX_MEMORY_RANGES macro */
+static int crash_max_memory_ranges;
+
+/*
+ * Used to save various memory ranges/regions needed for the captured
+ * kernel to boot. (lime memmap= option in other archs)
+ */
+mem_rgns_t usablemem_rgns = {0, NULL};
+
+/*
+ * To store the memory size of the first kernel and this value will be
+ * passed to the second kernel as command line (savemaxmem=xM).
+ * The second kernel will be calculated saved_max_pfn based on this
+ * variable.
+ * Since we are creating/using usable-memory property, there is no way
+ * we can determine the RAM size unless parsing the device-tree/memoy@/reg
+ * property in the kernel.
+ */
+unsigned long long saved_max_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running  kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+
+	int memory_ranges = 0;
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	char buf[MAXBYTES-1];
+	DIR *dir, *dmem;
+	FILE *file;
+	struct dirent *dentry, *mentry;
+	int i, n, crash_rng_len = 0;
+	unsigned long long start, end, cstart, cend;
+
+	crash_max_memory_ranges = max_memory_ranges + 6;
+	crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges;
+
+	crash_memory_range = (struct memory_range *) malloc(crash_rng_len);
+	if (!crash_memory_range) {
+		fprintf(stderr, "Allocation for crash memory range failed\n");
+		return -1;
+	}
+	memset(crash_memory_range, 0, crash_rng_len);
+
+	/* create a separate program header for the backup region */
+	crash_memory_range[0].start = BACKUP_SRC_START;
+	crash_memory_range[0].end = BACKUP_SRC_END + 1;
+	crash_memory_range[0].type = RANGE_RAM;
+	memory_ranges++;
+
+	dir = opendir(device_tree);
+	if (!dir) {
+		perror(device_tree);
+		goto err;
+	}
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7)
+		    && strcmp(dentry->d_name, "memory"))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		dmem = opendir(fname);
+		if (!dmem) {
+			perror(fname);
+			closedir(dir);
+			goto err;
+		}
+		while ((mentry = readdir(dmem)) != NULL) {
+			if (strcmp(mentry->d_name, "reg"))
+				continue;
+			strcat(fname, "/reg");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				closedir(dmem);
+				closedir(dir);
+				goto err;
+			}
+			n = fread(buf, 1, MAXBYTES, file);
+			if (n < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(dmem);
+				closedir(dir);
+				goto err;
+			}
+			if (memory_ranges >= (max_memory_ranges + 1)) {
+				/* No space to insert another element. */
+				fprintf(stderr,
+					"Error: Number of crash memory ranges"
+					" excedeed the max limit\n");
+				goto err;
+			}
+
+			/*
+			 * FIXME: This code fails on platforms that
+			 * have more than one memory range specified
+			 * in the device-tree's /memory/reg property.
+			 * or where the #address-cells and #size-cells
+			 * are not identical.
+			 *
+			 * We should interpret the /memory/reg property
+			 * based on the values of the #address-cells and
+			 * #size-cells properites.
+			 */
+			if (n == (sizeof(unsigned long) * 2)) {
+				start = ((unsigned long *)buf)[0];
+				end = start + ((unsigned long *)buf)[1];
+			} else {
+				start = ((unsigned long long *)buf)[0];
+				end = start + ((unsigned long long *)buf)[1];
+			}
+			if (start == 0 && end >= (BACKUP_SRC_END + 1))
+				start = BACKUP_SRC_END + 1;
+
+			cstart = crash_base;
+			cend = crash_base + crash_size;
+			/*
+			 * Exclude the region that lies within crashkernel
+			 */
+			if (cstart < end && cend > start) {
+				if (start < cstart && end > cend) {
+					crash_memory_range[memory_ranges].start
+						= start;
+					crash_memory_range[memory_ranges].end
+						= cstart;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+					crash_memory_range[memory_ranges].start
+						= cend;
+					crash_memory_range[memory_ranges].end
+						= end;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				} else if (start < cstart) {
+					crash_memory_range[memory_ranges].start
+						= start;
+					crash_memory_range[memory_ranges].end
+						= cstart;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				} else if (end > cend) {
+					crash_memory_range[memory_ranges].start
+						= cend;
+					crash_memory_range[memory_ranges].end
+						= end;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				}
+			} else {
+				crash_memory_range[memory_ranges].start = start;
+				crash_memory_range[memory_ranges].end  = end;
+				crash_memory_range[memory_ranges].type
+					= RANGE_RAM;
+				memory_ranges++;
+			}
+			fclose(file);
+		}
+		closedir(dmem);
+	}
+	closedir(dir);
+
+	/*
+	 * If RTAS region is overlapped with crashkernel, need to create ELF
+	 * Program header for the overlapped memory.
+	 */
+	if (crash_base < rtas_base + rtas_size &&
+		rtas_base < crash_base + crash_size) {
+		cstart = rtas_base;
+		cend = rtas_base + rtas_size;
+		if (cstart < crash_base)
+			cstart = crash_base;
+		if (cend > crash_base + crash_size)
+			cend = crash_base + crash_size;
+		crash_memory_range[memory_ranges].start = cstart;
+		crash_memory_range[memory_ranges++].end = cend;
+	}
+	/*
+	 * Can not trust the memory regions order that we read from
+	 * device-tree. Hence, get the MAX end value.
+	 */
+	for (i = 0; i < memory_ranges; i++)
+		if (saved_max_mem < crash_memory_range[i].end)
+			saved_max_mem = crash_memory_range[i].end;
+
+	*range = crash_memory_range;
+	*ranges = memory_ranges;
+#if DEBUG
+	int j;
+	printf("CRASH MEMORY RANGES\n");
+	for (j = 0; j < *ranges; j++) {
+		start = crash_memory_range[j].start;
+		end = crash_memory_range[j].end;
+		fprintf(stderr, "%016Lx-%016Lx\n", start, end);
+	}
+#endif
+	return 0;
+
+err:
+	if (crash_memory_range)
+		free(crash_memory_range);
+	return -1;
+}
+
+/* Converts unsigned long to ascii string. */
+static void ulltoa(unsigned long long i, char *str)
+{
+	int j = 0, k;
+	char tmp;
+
+	do {
+		str[j++] = i % 10 + '0';
+	} while ((i /= 10) > 0);
+	str[j] = '\0';
+
+	/* Reverse the string. */
+	for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+		tmp = str[k];
+		str[k] = str[j];
+		str[j] = tmp;
+	}
+}
+
+static int add_cmdline_param(char *cmdline, unsigned long long addr,
+				char *cmdstr, char *byte)
+{
+	int cmdlen, len, align = 1024;
+	char str[COMMAND_LINE_SIZE], *ptr;
+
+	/* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/
+	switch (byte[0]) {
+	case 'K':
+		if (addr%align)
+			return -1;
+		addr = addr/align;
+		break;
+	case 'M':
+		addr = addr/(align *align);
+		break;
+	}
+	ptr = str;
+	strcpy(str, cmdstr);
+	ptr += strlen(str);
+	ulltoa(addr, ptr);
+	strcat(str, byte);
+	len = strlen(str);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str);
+#if DEBUG
+	fprintf(stderr, "Command line after adding elfcorehdr: %s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Loads additional segments in case of a panic kernel is being loaded.
+ * One segment for backup region, another segment for storing elf headers
+ * for crash memory image.
+ */
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base)
+{
+	void *tmp;
+	unsigned long sz, elfcorehdr;
+	int nr_ranges, align = 1024, i;
+	unsigned long long end;
+	struct memory_range *mem_range;
+
+	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+		return -1;
+
+	/* Create a backup region segment to store backup data*/
+	sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
+	tmp = xmalloc(sz);
+	memset(tmp, 0, sz);
+	info->backup_start = add_buffer(info, tmp, sz, sz, align,
+					0, max_addr, 1);
+	reserve(info->backup_start, sz);
+
+	/* On powerpc memory ranges in device-tree is denoted as start
+	 * and size rather than start and end, as is the case with
+	 * other architectures like i386 . Because of this when loading
+	 * the memory ranges in crashdump-elf.c the filesz calculation
+	 * [ end - start + 1 ] goes for a toss.
+	 *
+	 * To be in sync with other archs adjust the end value for
+	 * every crash memory range before calling the generic function
+	 */
+
+	for (i = 0; i < nr_ranges; i++) {
+		end = crash_memory_range[i].end - 1;
+		crash_memory_range[i].end = end;
+	}
+
+
+#ifdef CONFIG_PPC64
+	/* Create elf header segment and store crash image data. */
+	if (arch_options.core_header_type == CORE_TYPE_ELF64) {
+		if (crash_create_elf64_headers(info, &elf_info64,
+					crash_memory_range, nr_ranges, &tmp,
+					&sz, ELF_CORE_HEADER_ALIGN) < 0)
+			return -1;
+	} else if (crash_create_elf32_headers(info, &elf_info32,
+				crash_memory_range, nr_ranges, &tmp, &sz,
+				ELF_CORE_HEADER_ALIGN) < 0)
+			return -1;
+#else
+	if (crash_create_elf32_headers(info, &elf_info32, crash_memory_range,
+				nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN)
+			< 0)
+		return -1;
+#endif
+
+	elfcorehdr = add_buffer(info, tmp, sz, sz, align,
+			min_base, max_addr, 1);
+	reserve(elfcorehdr, sz);
+	/* modify and store the cmdline in a global array. This is later
+	 * read by flatten_device_tree and modified if required
+	 */
+	add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K");
+	add_cmdline_param(mod_cmdline, saved_max_mem, " savemaxmem=", "M");
+	return 0;
+}
+
+/*
+ * Used to save various memory regions needed for the captured kernel.
+ */
+
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size)
+{
+	int i;
+	unsigned long long end = base + size;
+	unsigned long long ustart, uend;
+
+	base = _ALIGN_DOWN(base, getpagesize());
+	end = _ALIGN_UP(end, getpagesize());
+
+	for (i = 0; i < usablemem_rgns.size; i++) {
+		ustart = usablemem_rgns.ranges[i].start;
+		uend = usablemem_rgns.ranges[i].end;
+		if (base < uend && end > ustart) {
+			if ((base >= ustart) && (end <= uend))
+				return;
+			if (base < ustart && end > uend) {
+				usablemem_rgns.ranges[i].start = base;
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			} else if (base < ustart) {
+				usablemem_rgns.ranges[i].start = base;
+				return;
+			} else if (end > uend) {
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			}
+		}
+	}
+	usablemem_rgns.ranges[usablemem_rgns.size].start = base;
+	usablemem_rgns.ranges[usablemem_rgns.size++].end = end;
+
+#ifdef DEBUG
+	fprintf(stderr, "usable memory rgns size:%u base:%llx size:%llx\n",
+		usablemem_rgns.size, base, size);
+#endif
+}
+
+int is_crashkernel_mem_reserved(void)
+{
+	int fd;
+
+	fd = open("/proc/device-tree/chosen/linux,crashkernel-base", O_RDONLY);
+	if (fd < 0)
+		return 0;
+	close(fd);
+	return 1;
+}
+
diff --git a/kexec/arch/ppc/crashdump-powerpc.h b/kexec/arch/ppc/crashdump-powerpc.h
new file mode 100644
index 0000000..dc2772d
--- /dev/null
+++ b/kexec/arch/ppc/crashdump-powerpc.h
@@ -0,0 +1,38 @@
+#ifndef CRASHDUMP_POWERPC_H
+#define CRASHDUMP_POWERPC_H
+
+struct kexec_info;
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base);
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size);
+
+extern struct arch_options_t arch_options;
+
+#ifdef CONFIG_PPC64
+#define PAGE_OFFSET	0xC000000000000000UL
+#define VMALLOCBASE	0xD000000000000000UL
+#define MAXMEM		(-KERNELBASE-VMALLOCBASE)
+#else
+#define PAGE_OFFSET	0xC0000000
+#define MAXMEM		0x30000000 /* Use CONFIG_LOWMEM_SIZE from kernel */
+#endif
+
+#define KERNELBASE	PAGE_OFFSET
+#define __pa(x)		((unsigned long)(x)-PAGE_OFFSET)
+
+#define COMMAND_LINE_SIZE	512 /* from kernel */
+/* Backup Region, First 64K of System RAM. */
+#define BACKUP_SRC_START	0x0000
+#define BACKUP_SRC_END		0xffff
+#define BACKUP_SRC_SIZE		(BACKUP_SRC_END - BACKUP_SRC_START + 1)
+
+#define KDUMP_BACKUP_LIMIT	BACKUP_SRC_SIZE
+#define _ALIGN_UP(addr, size)	(((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr, size)	((addr)&(~((size)-1)))
+
+extern unsigned long long crash_base;
+extern unsigned long long crash_size;
+extern unsigned int rtas_base;
+extern unsigned int rtas_size;
+
+#endif /* CRASHDUMP_POWERPC_H */
diff --git a/kexec/arch/ppc/fs2dt.c b/kexec/arch/ppc/fs2dt.c
new file mode 100644
index 0000000..238a3f2
--- /dev/null
+++ b/kexec/arch/ppc/fs2dt.c
@@ -0,0 +1,460 @@
+/*
+ * fs2dt: creates a flattened device-tree
+ *
+ * Copyright (C) 2004,2005  Milton D Miller II, IBM Corporation
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com), IBM Corporation
+ *
+ * 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 (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "../../kexec.h"
+#include "kexec-ppc.h"
+
+#define MAXPATH			1024	/* max path name length */
+#define NAMESPACE		16384	/* max bytes for property names */
+#define TREEWORDS		65536	/* max 32 bit words for properties */
+#define MEMRESERVE		256	/* max number of reserved memory blks */
+#define MAX_MEMORY_RANGES	1024
+#define COMMAND_LINE_SIZE	512	/* from kernel */
+
+static char pathname[MAXPATH];
+static char propnames[NAMESPACE] = { 0 };
+static unsigned dtstruct[TREEWORDS], *dt;
+static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 };
+
+static int crash_param;
+static char local_cmdline[COMMAND_LINE_SIZE] = { "" };
+static unsigned *dt_len; /* changed len of modified cmdline
+			    in flat device-tree */
+static struct bootblock bb[1];
+
+void reserve(unsigned long long where, unsigned long long length)
+{
+	size_t offset;
+
+	for (offset = 0; mem_rsrv[offset + 1]; offset += 2)
+		;
+
+	if (offset + 4 >= 2 * MEMRESERVE)
+		die("unrecoverable error: exhasuted reservation meta data\n");
+
+	mem_rsrv[offset] = where;
+	mem_rsrv[offset + 1] = length;
+	mem_rsrv[offset + 3] = 0;  /* N.B: don't care about offset + 2 */
+}
+
+/* look for properties we need to reserve memory space for */
+static void checkprop(char *name, unsigned *data, int len)
+{
+	static unsigned long long base, size, end;
+
+	if ((data == NULL) && (base || size || end))
+		die("unrecoverable error: no property data");
+	else if (!strcmp(name, "linux,rtas-base"))
+		base = *data;
+	else if (!strcmp(name, "linux,tce-base"))
+		base = *(unsigned long long *) data;
+	else if (!strcmp(name, "rtas-size") ||
+			!strcmp(name, "linux,tce-size"))
+		size = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-start"))
+		if (len == 8)
+			base = *(unsigned long long *) data;
+		else
+			base = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-end"))
+		end = *(unsigned long long *) data;
+
+	if (size && end)
+		die("unrecoverable error: size and end set at same time\n");
+	if (base && size) {
+		reserve(base, size);
+		base = 0;
+		size = 0;
+	}
+	if (base && end) {
+		reserve(base, end-base);
+		base = 0;
+		end = 0;
+	}
+}
+
+/*
+ * return the property index for a property name, creating a new one
+ * if needed.
+ */
+static unsigned propnum(const char *name)
+{
+	unsigned offset = 0;
+
+	while (propnames[offset])
+		if (strcmp(name, propnames+offset))
+			offset += strlen(propnames+offset)+1;
+		else
+			return offset;
+
+	if (NAMESPACE - offset < strlen(name) + 1)
+		die("unrecoverable error: propnames overrun\n");
+
+	strcpy(propnames+offset, name);
+
+	return offset;
+}
+
+static void add_usable_mem_property(int fd, int len)
+{
+	char fname[MAXPATH], *bname;
+	unsigned long buf[2];
+	unsigned long ranges[2*MAX_MEMORY_RANGES];
+	unsigned long long base, end, loc_base, loc_end;
+	int range, rlen = 0;
+
+	strcpy(fname, pathname);
+	bname = strrchr(fname, '/');
+	bname[0] = '\0';
+	bname = strrchr(fname, '/');
+	if (strncmp(bname, "/memory@", 8) && strcmp(bname, "/memory"))
+		return;
+
+	if (len < 2 * sizeof(unsigned long))
+		die("unrecoverable error: not enough data for mem property\n");
+	len = 2 * sizeof(unsigned long);
+
+	if (lseek(fd, 0, SEEK_SET) < 0)
+		die("unrecoverable error: error seeking in \"%s\": %s\n",
+		    pathname, strerror(errno));
+	if (read(fd, buf, len) != len)
+		die("unrecoverable error: error reading \"%s\": %s\n",
+		    pathname, strerror(errno));
+
+	if (~0ULL - buf[0] < buf[1])
+		die("unrecoverable error: mem property overflow\n");
+	base = buf[0];
+	end = base + buf[1];
+
+	for (range = 0; range < usablemem_rgns.size; range++) {
+		loc_base = usablemem_rgns.ranges[range].start;
+		loc_end = usablemem_rgns.ranges[range].end;
+		if (loc_base >= base && loc_end <= end) {
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		} else if (base < loc_end && end > loc_base) {
+			if (loc_base < base)
+				loc_base = base;
+			if (loc_end > end)
+				loc_end = end;
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		}
+	}
+
+	if (!rlen) {
+		/*
+		 * User did not pass any ranges for thsi region. Hence, write
+		 * (0,0) duple in linux,usable-memory property such that
+		 * this region will be ignored.
+		 */
+		ranges[rlen++] = 0;
+		ranges[rlen++] = 0;
+	}
+
+	rlen = rlen * sizeof(unsigned long);
+	/*
+	 * No add linux,usable-memory property.
+	 */
+	*dt++ = 3;
+	*dt++ = rlen;
+	*dt++ = propnum("linux,usable-memory");
+	memcpy(dt, &ranges, rlen);
+	dt += (rlen + 3)/4;
+}
+
+/* put all properties (files) in the property structure */
+static void putprops(char *fn, struct dirent **nlist, int numlist)
+{
+	struct dirent *dp;
+	int i = 0, fd, len;
+	struct stat statbuf;
+
+	for (i = 0; i < numlist; i++) {
+		dp = nlist[i];
+		strcpy(fn, dp->d_name);
+
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+
+		if (lstat(pathname, &statbuf))
+			die("unrecoverable error: could not stat \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (!crash_param && !strcmp(fn, "linux,crashkernel-base"))
+			continue;
+
+		if (!crash_param && !strcmp(fn, "linux,crashkernel-size"))
+			continue;
+
+		/*
+		 * This property will be created for each node during kexec
+		 * boot. So, ignore it.
+		 */
+		if (!strcmp(dp->d_name, "linux,pci-domain") ||
+			!strcmp(dp->d_name, "linux,htab-base") ||
+			!strcmp(dp->d_name, "linux,htab-size") ||
+			!strcmp(dp->d_name, "linux,kernel-end") ||
+			!strcmp(dp->d_name, "linux,usable-memory"))
+				continue;
+
+		/* This property will be created/modified later in putnode()
+		 * So ignore it, unless we are reusing the initrd.
+		 */
+		if ((!strcmp(dp->d_name, "linux,initrd-start") ||
+		     !strcmp(dp->d_name, "linux,initrd-end")) &&
+		    !reuse_initrd)
+				continue;
+
+		if (!S_ISREG(statbuf.st_mode))
+			continue;
+
+		len = statbuf.st_size;
+
+		*dt++ = 3;
+		dt_len = dt;
+		*dt++ = len;
+		*dt++ = propnum(fn);
+
+		fd = open(pathname, O_RDONLY);
+		if (fd == -1)
+			die("unrecoverable error: could not open \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (read(fd, dt, len) != len)
+			die("unrecoverable error: could not read \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		checkprop(fn, dt, len);
+
+		/* Get the cmdline from the device-tree and modify it */
+		if (!strcmp(dp->d_name, "bootargs")) {
+			int cmd_len;
+			char temp_cmdline[COMMAND_LINE_SIZE] = { "" };
+			char *param = NULL;
+			cmd_len = strlen(local_cmdline);
+			if (cmd_len != 0) {
+				param = strstr(local_cmdline, "crashkernel=");
+				if (param)
+					crash_param = 1;
+				param = strstr(local_cmdline, "root=");
+			}
+			if (!param) {
+				char *old_param;
+				memcpy(temp_cmdline, dt, len);
+				param = strstr(temp_cmdline, "root=");
+				if (param) {
+					old_param = strtok(param, " ");
+					if (cmd_len != 0)
+						strcat(local_cmdline, " ");
+					strcat(local_cmdline, old_param);
+				}
+			}
+			strcat(local_cmdline, " ");
+			cmd_len = strlen(local_cmdline);
+			cmd_len = cmd_len + 1;
+			memcpy(dt, local_cmdline, cmd_len);
+			len = cmd_len;
+			*dt_len = cmd_len;
+#if	DEBUG
+			fprintf(stderr, "Modified cmdline:%s\n", local_cmdline);
+#endif
+		}
+
+		dt += (len + 3)/4;
+		if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size)
+			add_usable_mem_property(fd, len);
+		close(fd);
+	}
+
+	fn[0] = '\0';
+	checkprop(pathname, NULL, 0);
+}
+
+/*
+ * Compare function used to sort the device-tree directories
+ * This function will be passed to scandir.
+ */
+static int comparefunc(const void *dentry1, const void *dentry2)
+{
+	char *str1 = (*(struct dirent **)dentry1)->d_name;
+	char *str2 = (*(struct dirent **)dentry2)->d_name;
+
+	/*
+	 * strcmp scans from left to right and fails to idetify for some
+	 * strings such as memory@10000000 and memory@f000000.
+	 * Therefore, we get the wrong sorted order like memory@10000000 and
+	 * memory@f000000.
+	 */
+	if (strchr(str1, '@') && strchr(str2, '@') &&
+		(strlen(str1) > strlen(str2)))
+		return 1;
+
+	return strcmp(str1, str2);
+}
+
+/*
+ * put a node (directory) in the property structure.  first properties
+ * then children.
+ */
+static void putnode(void)
+{
+	char *dn;
+	struct dirent *dp;
+	char *basename;
+	struct dirent **namelist;
+	int numlist, i;
+	struct stat statbuf;
+
+	numlist = scandir(pathname, &namelist, 0, comparefunc);
+	if (numlist < 0)
+		die("unrecoverable error: could not scan \"%s\": %s\n",
+		    pathname, strerror(errno));
+	if (numlist == 0)
+		die("unrecoverable error: no directory entries in \"%s\"",
+		    pathname);
+
+	basename = strrchr(pathname, '/') + 1;
+
+	*dt++ = 1;
+	strcpy((void *)dt, *basename ? basename : "");
+	dt += strlen((void *)dt) / sizeof(unsigned) + 1;
+
+	strcat(pathname, "/");
+	dn = pathname + strlen(pathname);
+
+	putprops(dn, namelist, numlist);
+
+	/* Add initrd entries to the second kernel */
+	if (initrd_base && !strcmp(basename, "chosen/")) {
+		int len = 8;
+		unsigned long long initrd_end;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-start");
+
+		memcpy(dt, &initrd_base, len);
+		dt += (len + 3)/4;
+
+		len = 8;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-end");
+
+		initrd_end = initrd_base + initrd_size;
+
+		memcpy(dt, &initrd_end, len);
+		dt += (len + 3)/4;
+
+		reserve(initrd_base, initrd_size);
+	}
+
+	for (i = 0; i < numlist; i++) {
+		dp = namelist[i];
+		strcpy(dn, dp->d_name);
+		free(namelist[i]);
+
+		if (!strcmp(dn, ".") || !strcmp(dn, ".."))
+			continue;
+
+		if (lstat(pathname, &statbuf))
+			die("unrecoverable error: could not stat \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (S_ISDIR(statbuf.st_mode))
+			putnode();
+	}
+
+	*dt++ = 2;
+	dn[-1] = '\0';
+	free(namelist);
+}
+
+int create_flatten_tree(struct kexec_info *info, unsigned char **bufp,
+			unsigned long *sizep, char *cmdline)
+{
+	unsigned long len;
+	unsigned long tlen;
+	unsigned char *buf;
+	unsigned long me;
+
+	me = 0;
+
+	strcpy(pathname, "/proc/device-tree/");
+
+	dt = dtstruct;
+
+	if (cmdline)
+		strcpy(local_cmdline, cmdline);
+
+	putnode();
+	*dt++ = 9;
+
+	len = sizeof(bb[0]);
+	len += 7; len &= ~7;
+
+	bb->off_mem_rsvmap = len;
+
+	for (len = 1; mem_rsrv[len]; len += 2)
+		;
+	len += 3;
+	len *= sizeof(mem_rsrv[0]);
+
+	bb->off_dt_struct = bb->off_mem_rsvmap + len;
+
+	len = dt - dtstruct;
+	len *= sizeof(unsigned);
+	bb->dt_struct_size = len;
+	bb->off_dt_strings = bb->off_dt_struct + len;
+
+	len = propnum("");
+	bb->dt_strings_size = len;
+	len +=  3; len &= ~3;
+	bb->totalsize = bb->off_dt_strings + len;
+
+	bb->magic = 0xd00dfeed;
+	bb->version = 17;
+	bb->last_comp_version = 16;
+
+	reserve(me, bb->totalsize); /* patched later in kexec_load */
+
+	buf = (unsigned char *) malloc(bb->totalsize);
+	*bufp = buf;
+	memcpy(buf, bb, bb->off_mem_rsvmap);
+	tlen = bb->off_mem_rsvmap;
+	memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
+	tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
+	memcpy(buf+tlen, dtstruct,  bb->off_dt_strings - bb->off_dt_struct);
+	tlen = tlen +  (bb->off_dt_strings - bb->off_dt_struct);
+	memcpy(buf+tlen, propnames,  bb->totalsize - bb->off_dt_strings);
+	tlen = tlen + bb->totalsize - bb->off_dt_strings;
+	*sizep = tlen;
+	return 0;
+}
diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c
index a54a5d5..4bcac26 100644
--- a/kexec/arch/ppc/kexec-elf-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-ppc.c
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -23,15 +24,22 @@
 #include "../../kexec-elf.h"
 #include "kexec-ppc.h"
 #include <arch/options.h>
+#include "../../kexec-syscall.h"
+#include "crashdump-powerpc.h"
 
 #include "config.h"
 #include "fixup_dtb.h"
 
 static const int probe_debug = 0;
 
-#define MAX_COMMAND_LINE   256
+unsigned long long initrd_base, initrd_size;
+unsigned char reuse_initrd;
+const char *ramdisk;
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
+			char *);
 
 #define UPSZ(X) ((sizeof(X) + 3) & ~3)
+#ifdef WITH_GAMECUBE
 static struct boot_notes {
 	Elf_Bhdr hdr;
 	Elf_Nhdr bl_hdr;
@@ -65,7 +73,7 @@ static struct boot_notes {
 		.n_type = EBN_COMMAND_LINE,
 	},
 };
-
+#endif
 
 int elf_ppc_probe(const char *buf, off_t len)
 {
@@ -92,6 +100,7 @@ int elf_ppc_probe(const char *buf, off_t len)
 	return result;
 }
 
+#ifdef WITH_GAMECUBE
 static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 {
 	struct mem_phdr *phdr, *phdr_end;
@@ -112,6 +121,7 @@ static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 		phdr->p_paddr &= ~0xf0000000;	/* clear bits 0-3, ibm syntax */
 	}
 }
+#endif
 
 #define OPT_APPEND	(OPT_ARCH_MAX+0)
 #define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
@@ -145,10 +155,24 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 	struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
-	char *command_line;
+	char *command_line, *crash_cmdline, *cmdline_buf;
 	int command_line_len;
 	char *dtb;
 	int result;
+	unsigned long max_addr, hole_addr;
+	struct mem_phdr *phdr;
+	size_t size;
+	unsigned long long *rsvmap_ptr;
+	struct bootblock *bb_ptr;
+	unsigned int nr_segments;
+	unsigned long my_kernel, my_dt_offset;
+	unsigned long my_stack, my_backup_start;
+#ifdef CONFIG_PPC64
+	unsigned long toc_addr;
+#endif
+	unsigned int slave_code[256 / sizeof(unsigned int)], master_entry;
+	unsigned char *seg_buf = NULL;
+	off_t seg_size = 0;
 #ifdef WITH_GAMECUBE
 	int target_is_gamecube = 1;
 	char *arg_buf;
@@ -170,6 +194,9 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 
 	command_line = NULL;
 	dtb = NULL;
+	max_addr = LONG_MAX;
+	hole_addr = 0;
+
 	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch (opt) {
 		default:
@@ -209,15 +236,45 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 
 	fixup_nodes[cur_fixup] = NULL;
 
+	/* Need to append some command line parameters internally in case of
+	 * taking crash dumps.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		crash_cmdline = xmalloc(COMMAND_LINE_SIZE);
+		memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE);
+	} else
+		crash_cmdline = NULL;
+
 	/* Parse the Elf file */
 	result = build_elf_exec_info(buf, len, &ehdr, 0);
 	if (result < 0) {
 		free_elf_info(&ehdr);
 		return result;
 	}
+
+#ifdef WITH_GAMECUBE
 	if (target_is_gamecube) {
 		gamecube_hack_addresses(&ehdr);
 	}
+#endif
+
+	/* Load the Elf data. Physical load addresses in elf64 header do not
+	 * show up correctly. Use user supplied address for now to patch the
+	 * elf header
+	 */
+
+	phdr = &ehdr.e_phdr[0];
+	size = phdr->p_filesz;
+	if (size > phdr->p_memsz)
+		size = phdr->p_memsz;
+
+	hole_addr = locate_hole(info, size, 0, 0, max_addr, 1);
+#ifdef CONFIG_PPC64
+	ehdr.e_phdr[0].p_paddr = (Elf64_Addr)hole_addr;
+#else
+	ehdr.e_phdr[0].p_paddr = hole_addr;
+#endif
+
 	/* Load the Elf data */
 	result = elf_exec_load(&ehdr, info);
 	if (result < 0) {
@@ -225,6 +282,27 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		return result;
 	}
 
+	/* If panic kernel is being loaded, additional segments need
+	 * to be created.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		result = load_crashdump_segments(info, crash_cmdline,
+						max_addr, 0);
+		if (result < 0) {
+			free(crash_cmdline);
+			return -1;
+		}
+	}
+
+	cmdline_buf = xmalloc(COMMAND_LINE_SIZE);
+	memset((void *)cmdline_buf, 0, COMMAND_LINE_SIZE);
+	if (command_line)
+		strncat(cmdline_buf, command_line, command_line_len);
+	if (crash_cmdline)
+		strncat(cmdline_buf, crash_cmdline,
+				sizeof(crash_cmdline) -
+				strlen(crash_cmdline) - 1);
+
 	/*
 	 * In case of a toy we take the hardcoded things and an easy setup via
 	 * one of the assembly startups. Every thing else should be grown up
@@ -269,31 +347,105 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		blob_buf = slurp_file(dtb, &blob_size);
 		if (!blob_buf || !blob_size)
 			die("Device tree seems to be an empty file.\n");
-		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, command_line);
+		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes,
+				cmdline_buf);
 		dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
 				KERNEL_ACCESS_TOP, -1);
 	} else {
-		dtb_addr = 0;
+		/* create from fs2dt */
+		seg_buf = NULL;
+		seg_size = 0;
+		create_flatten_tree(info, (unsigned char **)&seg_buf,
+				(unsigned long *)&seg_size, cmdline_buf);
+		add_buffer(info, seg_buf, seg_size, seg_size,
+#ifdef CONFIG_PPC64
+				0, 0,  max_addr, -1);
+#else
+		/* load dev tree at 16 Mb offset from kernel load address */
+			0, 0, ehdr.e_phdr[0].p_paddr + SIZE_16M, -1);
+#endif
 	}
 
-	/* set various variables for the purgatory */
-	addr = ehdr.e_entry;
-	elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
 
-	addr = dtb_addr;
-	elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
+	if (dtb) {
+		/* set various variables for the purgatory */
+		addr = ehdr.e_entry;
+		elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
+
+		addr = dtb_addr;
+		elf_rel_set_symbol(&info->rhdr, "dt_offset",
+						&addr, sizeof(addr));
 
-	addr = rmo_top;
-	elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
+		addr = rmo_top;
+
+		elf_rel_set_symbol(&info->rhdr, "mem_size",
+						&addr, sizeof(addr));
 
 #define PUL_STACK_SIZE	(16 * 1024)
-	addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1);
-	addr += PUL_STACK_SIZE;
-	elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
+		addr = locate_hole(info, PUL_STACK_SIZE, 0, 0,
+				elf_max_addr(&ehdr), 1);
+		addr += PUL_STACK_SIZE;
+		elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr));
 #undef PUL_STACK_SIZE
 
-	addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
-	info->entry = (void *)addr;
+		addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
+		info->entry = (void *)addr;
+
+	} else { /*from fs2dt*/
+
+		/* patch reserve map address for flattened device-tree
+		 * find last entry (both 0) in the reserve mem list.  Assume DT
+		 * entry is before this one
+		 */
+		bb_ptr = (struct bootblock *)(
+			(unsigned char *)info->segment[(info->nr_segments) -
+				1].buf);
+		rsvmap_ptr = (unsigned long long *)(
+			(unsigned char *)info->segment[(info->nr_segments) -
+				1].buf + bb_ptr->off_mem_rsvmap);
+		while (*rsvmap_ptr || *(rsvmap_ptr + 1))
+			rsvmap_ptr += 2;
+		rsvmap_ptr -= 2;
+		*rsvmap_ptr = (unsigned long)(
+				info->segment[(info->nr_segments)-1].mem);
+		rsvmap_ptr++;
+		*rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
+
+		nr_segments = info->nr_segments;
+
+		/* Set kernel */
+		my_kernel = (unsigned long)info->segment[0].mem;
+		elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel,
+				sizeof(my_kernel));
+
+		/* Set dt_offset */
+		my_dt_offset = (unsigned long)info->segment[nr_segments -
+			1].mem;
+		elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+				sizeof(my_dt_offset));
+
+		/* get slave code from new kernel, put in purgatory */
+		elf_rel_get_symbol(&info->rhdr, "purgatory_start", slave_code,
+				sizeof(slave_code));
+		master_entry = slave_code[0];
+		memcpy(slave_code, info->segment[0].buf, sizeof(slave_code));
+		slave_code[0] = master_entry;
+		elf_rel_set_symbol(&info->rhdr, "purgatory_start", slave_code,
+				sizeof(slave_code));
+
+		/* Set stack address */
+		my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1);
+		my_stack += 16*1024;
+		elf_rel_set_symbol(&info->rhdr, "stack", &my_stack,
+				sizeof(my_stack));
+	}
+
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		/* Set backup address */
+		my_backup_start = info->backup_start;
+		elf_rel_set_symbol(&info->rhdr, "backup_start",
+				&my_backup_start, sizeof(my_backup_start));
+	}
 #endif
 	return 0;
 }
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index f552d79..aabc02f 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -21,6 +21,7 @@
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
 #include "kexec-ppc.h"
+#include "crashdump-powerpc.h"
 #include <arch/options.h>
 
 #include "config.h"
@@ -45,13 +46,14 @@ static int get_memory_ranges_gc(struct memory_range **range, int *ranges,
 }
 #else
 static int use_new_dtb;
-static int max_memory_ranges;
+int max_memory_ranges;
 static int nr_memory_ranges, nr_exclude_ranges;
 static struct memory_range *exclude_range;
 static struct memory_range *memory_range;
 static struct memory_range *base_memory_range;
 static uint64_t memory_max;
 uint64_t rmo_top;
+unsigned long long crash_base, crash_size;
 unsigned int rtas_base, rtas_size;
 
 /*
@@ -174,7 +176,40 @@ static int sort_base_ranges(void)
 
 #define MAXBYTES 128
 
-/* Get base memory ranges */
+static int realloc_memory_ranges(void)
+{
+	size_t memory_range_len;
+
+	max_memory_ranges++;
+	memory_range_len = sizeof(struct memory_range) * max_memory_ranges;
+
+	memory_range = (struct memory_range *) malloc(memory_range_len);
+	if (!memory_range)
+		goto err;
+
+	base_memory_range = (struct memory_range *) realloc(memory_range,
+			memory_range_len);
+	if (!base_memory_range)
+		goto err;
+
+	exclude_range = (struct memory_range *) realloc(exclude_range,
+			memory_range_len);
+	if (!exclude_range)
+		goto err;
+
+	usablemem_rgns.ranges = (struct memory_range *)
+				realloc(usablemem_rgns.ranges,
+						memory_range_len);
+	if (!(usablemem_rgns.ranges))
+		goto err;
+
+	return 0;
+
+err:
+	fprintf(stderr, "memory range structure re-allocation failure\n");
+	return -1;
+}
+
 static int get_base_ranges(void)
 {
 	int local_memory_ranges = 0;
@@ -219,8 +254,10 @@ static int get_base_ranges(void)
 				return -1;
 			}
 			if (local_memory_ranges >= max_memory_ranges) {
-				fclose(file);
-				break;
+				if (realloc_memory_ranges() < 0){
+	-				fclose(file);
+					break;
+				}
 			}
 			base_memory_range[local_memory_ranges].start =
 				((uint32_t *)buf)[0];
@@ -250,16 +287,23 @@ static int get_base_ranges(void)
 /* Get devtree details and create exclude_range array
  * Also create usablemem_ranges for KEXEC_ON_CRASH
  */
-static int get_devtree_details(unsigned long UNUSED(kexec_flags))
+static int get_devtree_details(unsigned long kexec_flags)
 {
 	uint64_t rmo_base;
-	char buf[MAXBYTES];
+	unsigned long long tce_base;
+	unsigned int tce_size;
+	unsigned long long htab_base, htab_size;
+	unsigned long long kernel_end;
+	unsigned long long initrd_start, initrd_end;
+	char buf[MAXBYTES-1];
 	char device_tree[256] = "/proc/device-tree/";
 	char fname[256];
 	DIR *dir, *cdir;
 	FILE *file;
 	struct dirent *dentry;
+	struct stat fstat;
 	int n, i = 0;
+	unsigned long tmp_long;
 
 	if ((dir = opendir(device_tree)) == NULL) {
 		perror(device_tree);
@@ -269,10 +313,10 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 	while ((dentry = readdir(dir)) != NULL) {
 		if (strncmp(dentry->d_name, "chosen", 6) &&
 				strncmp(dentry->d_name, "memory@", 7) &&
-				strcmp(dentry->d_name, "memory") &&
+				strncmp(dentry->d_name, "memory", 6) &&
+				strncmp(dentry->d_name, "pci@", 4) &&
 				strncmp(dentry->d_name, "rtas", 4))
 			continue;
-
 		strcpy(fname, device_tree);
 		strcat(fname, dentry->d_name);
 		if ((cdir = opendir(fname)) == NULL) {
@@ -280,13 +324,172 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			goto error_opendir;
 		}
 
+		if (strncmp(dentry->d_name, "chosen", 6) == 0) {
+			strcat(fname, "/linux,kernel-end");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&tmp_long, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			kernel_end = tmp_long;
+			fclose(file);
+
+			/* Add kernel memory to exclude_range */
+			exclude_range[i].start = 0x0UL;
+			exclude_range[i].end = kernel_end;
+			i++;
+			if (i >= max_memory_ranges)
+				realloc_memory_ranges();
+			if (kexec_flags & KEXEC_ON_CRASH) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-base");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				if (fread(&tmp_long, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				crash_base = tmp_long;
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-size");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				if (fread(&tmp_long, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				crash_size = tmp_long;
+
+				if (crash_base > mem_min)
+					mem_min = crash_base;
+				if (crash_base + crash_size < mem_max)
+					mem_max = crash_base + crash_size;
+
+				add_usable_mem_rgns(0, crash_base + crash_size);
+				reserve(KDUMP_BACKUP_LIMIT,
+						crash_base-KDUMP_BACKUP_LIMIT);
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-base");
+			file = fopen(fname, "r");
+			if (!file) {
+				closedir(cdir);
+				if (errno == ENOENT) {
+					/* Non LPAR */
+					errno = 0;
+					continue;
+				}
+				perror(fname);
+				goto error_opendir;
+			}
+			if (fread(&htab_base, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-size");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&htab_size, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			/* Add htab address to exclude_range - NON-LPAR only */
+			exclude_range[i].start = htab_base;
+			exclude_range[i].end = htab_base + htab_size;
+			i++;
+			if (i >= max_memory_ranges)
+				realloc_memory_ranges();
+
+			/* reserve the initrd_start and end locations. */
+			if (reuse_initrd) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-start");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, &fstat) != 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (fread(&initrd_start, fstat.st_size, 1, file)
+						!= 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-end");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, &fstat) != 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (fread(&initrd_end, fstat.st_size, 1, file)
+						!= 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				fclose(file);
+
+				/* Add initrd address to exclude_range */
+				exclude_range[i].start = initrd_start;
+				exclude_range[i].end = initrd_end;
+				i++;
+				if (i >= max_memory_ranges)
+					realloc_memory_ranges();
+			}
+		} /* chosen */
+
 		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
 			strcat(fname, "/linux,rtas-base");
 			if ((file = fopen(fname, "r")) == NULL) {
 				perror(fname);
 				goto error_opencdir;
 			}
-			if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) {
+			if (fread(&rtas_base, sizeof(unsigned int), 1, file)
+					!= 1) {
 				perror(fname);
 				goto error_openfile;
 			}
@@ -298,7 +501,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 				perror(fname);
 				goto error_opencdir;
 			}
-			if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) {
+			if (fread(&rtas_size, sizeof(unsigned int), 1, file)
+					!= 1) {
 				perror(fname);
 				goto error_openfile;
 			}
@@ -307,6 +511,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			exclude_range[i].start = rtas_base;
 			exclude_range[i].end = rtas_base + rtas_size;
 			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(rtas_base, rtas_size);
 		} /* rtas */
 
 		if (!strncmp(dentry->d_name, "memory@", 7) ||
@@ -336,6 +542,48 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			fclose(file);
 			closedir(cdir);
 		} /* memory */
+
+		if (strncmp(dentry->d_name, "pci@", 4) == 0) {
+			strcat(fname, "/linux,tce-base");
+			file = fopen(fname, "r");
+			if (!file) {
+				closedir(cdir);
+				if (errno == ENOENT) {
+					/* Non LPAR */
+					errno = 0;
+					continue;
+				}
+				perror(fname);
+				goto error_opendir;
+			}
+			if (fread(&tce_base, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+				return -1;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,tce-size");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&tce_size, sizeof(unsigned int), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			/* Add tce to exclude_range - NON-LPAR only */
+			exclude_range[i].start = tce_base;
+			exclude_range[i].end = tce_base + tce_size;
+			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(tce_base, tce_size);
+			closedir(cdir);
+		} /* pci */
 	}
 	closedir(dir);
 
@@ -347,8 +595,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 	int k;
 	for (k = 0; k < i; k++)
 		fprintf(stderr, "exclude_range sorted exclude_range[%d] "
-				"start:%llx, end:%llx\n", k, exclude_range[k].start,
-				exclude_range[k].end);
+			"start:%llx, end:%llx\n", k, exclude_range[k].start,
+			exclude_range[k].end);
 #endif
 	return 0;
 
@@ -532,7 +780,3 @@ void arch_update_purgatory(struct kexec_info *UNUSED(info))
 {
 }
 
-int is_crashkernel_mem_reserved(void)
-{
-	return 0; /* kdump is not supported on this platform (yet) */
-}
diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h
index 6cec467..fc0471f 100644
--- a/kexec/arch/ppc/kexec-ppc.h
+++ b/kexec/arch/ppc/kexec-ppc.h
@@ -1,6 +1,11 @@
 #ifndef KEXEC_PPC_H
 #define KEXEC_PPC_H
 
+#define MAXBYTES	128
+#define MAX_LINE	160
+#define CORE_TYPE_ELF32	1
+#define CORE_TYPE_ELF64	2
+
 extern unsigned char setup_simple_start[];
 extern uint32_t setup_simple_size;
 
@@ -16,6 +21,8 @@ extern struct {
 	uint32_t spr8;
 } setup_dol_regs;
 
+#define SIZE_16M	(16*1024*1024UL)
+
 int elf_ppc_probe(const char *buf, off_t len);
 int elf_ppc_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
@@ -37,4 +44,29 @@ void dol_ppc_usage(void);
  */
 #define KERNEL_ACCESS_TOP (24 * 1024 * 1024)
 
+/* boot block version 17 as defined by the linux kernel */
+struct bootblock {
+	unsigned magic,
+		totalsize,
+		off_dt_struct,
+		off_dt_strings,
+		off_mem_rsvmap,
+		version,
+		last_comp_version,
+		boot_physid,
+		dt_strings_size,
+		dt_struct_size;
+};
+
+typedef struct mem_rgns {
+	unsigned int size;
+	struct memory_range *ranges;
+} mem_rgns_t;
+extern mem_rgns_t usablemem_rgns;
+extern int max_memory_ranges;
+extern unsigned long long initrd_base, initrd_size;
+extern unsigned char reuse_initrd;
+#define COMMAND_LINE_SIZE	512 /* from kernel */
+/*fs2dt*/
+void reserve(unsigned long long where, unsigned long long length);
 #endif /* KEXEC_PPC_H */
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
index 0dd18b6..72289a0 100644
--- a/purgatory/arch/ppc/Makefile
+++ b/purgatory/arch/ppc/Makefile
@@ -2,7 +2,7 @@
 # Purgatory ppc
 #
 
-ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap.S
+ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap_32.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c
diff --git a/purgatory/arch/ppc/purgatory-ppc.c b/purgatory/arch/ppc/purgatory-ppc.c
index 01d0f38..3d7d484 100644
--- a/purgatory/arch/ppc/purgatory-ppc.c
+++ b/purgatory/arch/ppc/purgatory-ppc.c
@@ -1,19 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * 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 (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
 #include <purgatory.h>
 #include "purgatory-ppc.h"
 
-unsigned int pul_stack = 0;
-unsigned int dt_offset = 0;
-unsigned int kernel = 0;
-unsigned int epapr_magic = 0;
-unsigned int mem_size = 0;
+unsigned int panic_kernel = 0;
+unsigned long backup_start = 0;
+unsigned long stack = 0;
+unsigned long dt_offset = 0;
+unsigned long my_toc = 0;
+unsigned long kernel = 0;
 
 void setup_arch(void)
 {
-	/* Nothing for now */
+	return;
 }
 
-/* This function can be used to execute after the SHA256 verification. */
 void post_verification_setup_arch(void)
 {
-	/* Nothing for now */
+	if (panic_kernel)
+		crashdump_backup_memory();
 }
diff --git a/purgatory/arch/ppc/purgatory-ppc.h b/purgatory/arch/ppc/purgatory-ppc.h
index e931cae..7eff8aa 100644
--- a/purgatory/arch/ppc/purgatory-ppc.h
+++ b/purgatory/arch/ppc/purgatory-ppc.h
@@ -1,6 +1,6 @@
 #ifndef PURGATORY_PPC_H
 #define PURGATORY_PPC_H
 
-/* nothing yet */
-
+void crashdump_backup_memory(void);
+void post_verification_setup_arch(void);
 #endif /* PURGATORY_PPC_H */
diff --git a/purgatory/arch/ppc/v2wrap.S b/purgatory/arch/ppc/v2wrap.S
deleted file mode 100644
index 79d188f..0000000
--- a/purgatory/arch/ppc/v2wrap.S
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-#  kexec: Linux boots Linux
-#
-#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
-#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
-#  Copyright (C) 2008, Sebastian Andrzej Siewior (bigeasy@linutronix.de), linutronix
-#
-#  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 (version 2 of the License).
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-#include "ppc_asm.h"
-
-# v2wrap.S
-# a wrapper to call purgatory code
-# Invokes ppc kernel with the arguments according to ePAPR v1.0
-# It assumes that the MSR is allready correct.
-
-# calling convention:
-#  no register are considred
-#
-
-#define LOADADDR(rn,name)	\
-	lis     rn,name##@h;	\
-	ori     rn,rn,name##@l;	\
-
-	.globl purgatory_start
-purgatory_start:
-
-	LOADADDR(r6,pul_stack)
-	lwz	r1,0(r6)		#setup stack
-
-	subi	r1, r1, 112
-	bl	purgatory
-	nop
-
-	LOADADDR(r6,kernel)
-	lwz	r4,0(r6)		# load the kernel address
-	mtlr	r4			# prepare branch too
-
-	LOADADDR(r6, dt_offset)
-	lwz	r3, 0(r6)		# load device-tree address
-
-	li	r4, 0
-	li	r5, 0
-
-	LOADADDR(r6, epapr_magic)	# ePAPR magic value
-	lwz	r6, 0(r6)
-
-	LOADADDR(r7, mem_size)		# the Initial Mapped Area
-	lwz	r7, 0(r6)
-
-	li	r8, 0
-	li	r9, 0
-
-	blr				# start kernel
diff --git a/purgatory/arch/ppc/v2wrap_32.S b/purgatory/arch/ppc/v2wrap_32.S
new file mode 100644
index 0000000..8442d16
--- /dev/null
+++ b/purgatory/arch/ppc/v2wrap_32.S
@@ -0,0 +1,91 @@
+#
+#  kexec: Linux boots Linux
+#
+#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
+#
+#  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 (version 2 of the License).
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# v2wrap.S
+# a wrapper to call purgatory code to backup first
+# 32kB of first kernel into the backup region
+# reserved by kexec-tools.
+# Invokes powerpc kernel with the expected arguments
+# of kernel(device-tree, phys-offset, 0)
+
+#
+# calling convention:
+#   r3 = physical number of this cpu (all cpus)
+#   r4 = address of this chunk (master only)
+# master enters at purgatory_start (aka first byte of this chunk)
+# slaves (additional cpus), if any, enter a copy of the
+# first 0x100 bytes of this code relocated to 0x0
+#
+# in other words,
+#   a copy of the first 0x100 bytes of this code is copied to 0
+#   and the slaves are sent to address 0x60
+#   with r3 = their physical cpu number.
+
+	.globl purgatory_start
+purgatory_start:	b	master
+	.org purgatory_start + 0x60     # ABI: slaves start at 60 with r3=phys
+slave:	b $
+	.org purgatory_start + 0x100    # ABI: end of copied region
+	.size purgatory_start, . - purgatory_start
+
+#
+# The above 0x100 bytes at purgatory_start are replaced with the
+# code from the kernel (or next stage) by kexec/arch/powerpc/kexec-powerpc.c
+#
+
+master:
+	or	1,1,1		# low priority to let other threads catchup
+	isync
+	mr      17,3            # save cpu id to r17
+	mr      15,4            # save physical address in reg15
+
+	lis	6,stack@h
+	ori	6,6,stack@l
+	lwz     1,0(6)          #setup stack
+
+	subi    1,1,112
+	bl      purgatory
+	nop
+
+	or	3,3,3		# ok now to high priority, lets boot
+	lis	6,0x1
+	mtctr	6		# delay a bit for slaves to catch up
+83:	bdnz	83b		# before we overwrite 0-100 again
+
+	lis	6,dt_offset@h
+	ori	6,6,dt_offset@l
+	lwz     3,0(6)          # load device-tree address
+	lwz     6,20(3)         # fetch version number
+	cmpwi   0,6,2           # v2 ?
+	blt     80f
+	stw     17,28(3)        # save my cpu number as boot_cpu_phys
+80:
+	lis	6,kernel@h
+	ori	6,6,kernel@l
+	lwz     4,0(6)          # load the kernel address
+	li	5,0		# r5 will be 0 for kernel
+	li	6,0		# clear r6 for good measure
+	mtctr	4		# prepare branch too
+
+	lwz	8,0(4)		# get the first instruction that we stole
+	stw	8,0(0)		# and put it in the slave loop at 0
+				# skip cache flush, do we care?
+
+	bctr			# start kernel

^ permalink raw reply related

* [PATCH] [POWEPC] crashdump: do not fail on null pointer dereferencing
From: Maxim Uvarov @ 2010-05-11 15:41 UTC (permalink / raw)
  To: linuxppc-dev, linux-kernel, uvarov

Best regards,
Maxim Uvarov.

From: Maxim Uvarov <muvarov@gmail.com>

Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
---

 arch/powerpc/kernel/crash.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 6f4613d..341d8af 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -375,6 +375,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
 	for_each_irq(i) {
 		struct irq_desc *desc = irq_to_desc(i);
 
+		if (!desc || !desc->chip || !desc->chip->eoi)
+			continue;
+
 		if (desc->status & IRQ_INPROGRESS)
 			desc->chip->eoi(i);
 

^ permalink raw reply related

* Re: [RFC][PATCH 0/12] KVM, x86, ppc, asm-generic: moving dirty bitmaps to user space
From: Alexander Graf @ 2010-05-11 15:55 UTC (permalink / raw)
  To: Takuya Yoshikawa
  Cc: linux-arch, x86, arnd, kvm, kvm-ia64, fernando, mtosatti,
	linux-kernel, kvm-ppc, yoshikawa.takuya, linuxppc-dev, mingo,
	paulus, avi, hpa, tglx
In-Reply-To: <20100504215645.6448af8f.takuya.yoshikawa@gmail.com>

Takuya Yoshikawa wrote:
> Hi, sorry for sending from my personal account.
> The following series are all from me:
>
>   From: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
>
>   The 3rd version of "moving dirty bitmaps to user space".
>
> From this version, we add x86 and ppc and asm-generic people to CC lists.
>
>
> [To KVM people]
>
> Sorry for being late to reply your comments.
>
> Avi,
>  - I've wrote an answer to your question in patch 5/12: drivers/vhost/vhost.c .
>
>  - I've considered to change the set_bit_user_non_atomic to an inline function,
>    but did not change because the other helpers in the uaccess.h are written as
>    macros. Anyway, I hope that x86 people will give us appropriate suggestions
>    about this.
>
>  - I thought that documenting about making bitmaps 64-bit aligned will be
>    written when we add an API to register user-allocated bitmaps. So probably
>    in the next series.
>
> Avi, Alex,
>  - Could you check the ia64 and ppc parts, please? I tried to keep the logical
>    changes as small as possible.
>
>    I personally tried to build these with cross compilers. For ia64, I could check
>    build success with my patch series. But book3s, even without my patch series,
>    it failed with the following errors:
>
>   arch/powerpc/kvm/book3s_paired_singles.c: In function 'kvmppc_emulate_paired_single':
>   arch/powerpc/kvm/book3s_paired_singles.c:1289: error: the frame size of 2288 bytes is larger than 2048 bytes
>   make[1]: *** [arch/powerpc/kvm/book3s_paired_singles.o] Error 1
>   make: *** [arch/powerpc/kvm] Error 2
>   

This is bad. I haven't encountered that one at all so far, but I guess
my compiler version is different from yours. Sigh.

>
> About changelog: there are two main changes from the 2nd version:
>   1. I changed the treatment of clean slots (see patch 1/12).
>      This was already applied today, thanks!
>   2. I changed the switch API. (see patch 11/12).
>
> To show this API's advantage, I also did a test (see the end of this mail).
>
>
> [To x86 people]
>
> Hi, Thomas, Ingo, Peter,
>
> Please review the patches 4,5/12. Because this is the first experience for
> me to send patches to x86, please tell me if this lacks anything.
>
>
> [To ppc people]
>
> Hi, Benjamin, Paul, Alex,
>
> Please see the patches 6,7/12. I first say sorry for that I've not tested these
> yet. In that sense, these may not be in the quality for precise reviews. But I
> will be happy if you would give me any comments.
>
> Alex, could you help me? Though I have a plan to get PPC box in the future,
> currently I cannot test these.
>   

Could you please point me to a git tree where everything's readily
applied? That would make testing a lot easier.

Alex

^ permalink raw reply

* Re: [RFC][PATCH 7/12 not tested yet] PPC: introduce __set_bit() like function for bitmaps in user space
From: Alexander Graf @ 2010-05-11 16:00 UTC (permalink / raw)
  To: Takuya Yoshikawa
  Cc: linux-arch, x86, arnd, kvm, kvm-ia64, fernando, mtosatti,
	linux-kernel, kvm-ppc, yoshikawa.takuya, linuxppc-dev, mingo,
	paulus, avi, hpa, tglx
In-Reply-To: <20100504220418.083929bc.takuya.yoshikawa@gmail.com>

Takuya Yoshikawa wrote:
> During the work of KVM's dirty page logging optimization, we encountered
> the need of manipulating bitmaps in user space efficiantly. To achive this,
> we introduce a uaccess function for setting a bit in user space following
> Avi's suggestion.
>
>   KVM is now using dirty bitmaps for live-migration and VGA. Although we need
>   to update them from kernel side, copying them every time for updating the
>   dirty log is a big bottleneck. Especially, we tested that zero-copy bitmap
>   manipulation improves responses of GUI manipulations a lot.
>
> We also found one similar need in drivers/vhost/vhost.c in which the author
> implemented set_bit_to_user() locally using inefficient functions: see TODO
> at the top of that.
>
> Probably, this kind of need would be common for virtualization area.
>
> So we introduce a function set_bit_user_non_atomic().
>
> Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
> Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
> CC: Alexander Graf <agraf@suse.de>
> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> CC: Paul Mackerras <paulus@samba.org>
> ---
>  arch/powerpc/include/asm/uaccess.h |   19 +++++++++++++++++++
>  1 files changed, 19 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
> index 3a01ce8..f878326 100644
> --- a/arch/powerpc/include/asm/uaccess.h
> +++ b/arch/powerpc/include/asm/uaccess.h
> @@ -321,6 +321,25 @@ do {								\
>  	__gu_err;						\
>  })
>  
> +static inline int set_bit_user_non_atomic(int nr, void __user *addr)
> +{
> +	u8 __user *p;
> +	u8 val;
> +
> +	p = (u8 __user *)((unsigned long)addr + nr / BITS_PER_BYTE);
>   

Does C do the + or the / first? Either way, I'd like to see brackets here :)


Alex

^ permalink raw reply

* Re: [PATCH] [POWEPC] crashdump: do not fail on null pointer dereferencing
From: Vitaly Wool @ 2010-05-11 16:02 UTC (permalink / raw)
  To: Maxim Uvarov; +Cc: uvarov, linuxppc-dev, linux-kernel
In-Reply-To: <20100511154108.11546.12066.stgit@muvarov>

Hi,

> diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
> index 6f4613d..341d8af 100644
> --- a/arch/powerpc/kernel/crash.c
> +++ b/arch/powerpc/kernel/crash.c
> @@ -375,6 +375,9 @@ void default_machine_crash_shutdown(struct pt_regs *r=
egs)
> =A0 =A0 =A0 =A0for_each_irq(i) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct irq_desc *desc =3D irq_to_desc(i);
>
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!desc || !desc->chip || !desc->chip->eo=
i)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> +

Kinda unlikely that desc can be NULL here :)

~Vitaly

^ permalink raw reply

* [PATCH 1/2] Fix kexec on powerpc32
From: Maxim Uvarov @ 2010-05-11 17:47 UTC (permalink / raw)
  To: linuxppc-dev, kexec, uvarov; +Cc: lists, horms


This patch is required in case if you are using new toolchains.

Best regards,
Maxim Uvarov.

From: Maxim Uvarov <muvarov@gmail.com>

Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
---

 kexec/arch/ppc/Makefile            |    2 
 kexec/arch/ppc/crashdump-powerpc.c |  439 ++++++++++++++++++++++++++++++++++
 kexec/arch/ppc/crashdump-powerpc.h |   38 +++
 kexec/arch/ppc/fs2dt.c             |  460 ++++++++++++++++++++++++++++++++++++
 kexec/arch/ppc/kexec-elf-ppc.c     |  186 +++++++++++++--
 kexec/arch/ppc/kexec-ppc.c         |  276 ++++++++++++++++++++--
 kexec/arch/ppc/kexec-ppc.h         |   32 +++
 purgatory/arch/ppc/Makefile        |    2 
 purgatory/arch/ppc/purgatory-ppc.c |   38 ++-
 purgatory/arch/ppc/purgatory-ppc.h |    4 
 purgatory/arch/ppc/v2wrap.S        |   66 -----
 purgatory/arch/ppc/v2wrap_32.S     |   91 +++++++
 12 files changed, 1524 insertions(+), 110 deletions(-)
 create mode 100644 kexec/arch/ppc/crashdump-powerpc.c
 create mode 100644 kexec/arch/ppc/crashdump-powerpc.h
 create mode 100644 kexec/arch/ppc/fs2dt.c
 delete mode 100644 purgatory/arch/ppc/v2wrap.S
 create mode 100644 purgatory/arch/ppc/v2wrap_32.S

diff --git a/kexec/arch/ppc/Makefile b/kexec/arch/ppc/Makefile
index 1c7441c..5988213 100644
--- a/kexec/arch/ppc/Makefile
+++ b/kexec/arch/ppc/Makefile
@@ -11,6 +11,8 @@ ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-uImage-ppc.c
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S
 ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/fs2dt.c
+ppc_KEXEC_SRCS += kexec/arch/ppc/crashdump-powerpc.c
 ppc_KEXEC_SRCS += kexec/kexec-uImage.c
 
 libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c
diff --git a/kexec/arch/ppc/crashdump-powerpc.c b/kexec/arch/ppc/crashdump-powerpc.c
new file mode 100644
index 0000000..7bfad20
--- /dev/null
+++ b/kexec/arch/ppc/crashdump-powerpc.c
@@ -0,0 +1,439 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <elf.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "../../crashdump.h"
+#include "kexec-ppc.h"
+#include "crashdump-powerpc.h"
+
+#ifdef CONFIG_PPC64
+static struct crash_elf_info elf_info64 = {
+class: ELFCLASS64,
+data: ELFDATA2MSB,
+machine: EM_PPC64,
+backup_src_start: BACKUP_SRC_START,
+backup_src_end: BACKUP_SRC_END,
+page_offset: PAGE_OFFSET,
+lowmem_limit: MAXMEM,
+};
+#endif
+static struct crash_elf_info elf_info32 = {
+class: ELFCLASS32,
+data: ELFDATA2MSB,
+#ifdef CONFIG_PPC64
+machine: EM_PPC64,
+#else
+machine: EM_PPC,
+#endif
+backup_src_start: BACKUP_SRC_START,
+backup_src_end: BACKUP_SRC_END,
+page_offset: PAGE_OFFSET,
+lowmem_limit: MAXMEM,
+};
+
+/* Stores a sorted list of RAM memory ranges for which to create elf headers.
+ * A separate program header is created for backup region
+ */
+static struct memory_range *crash_memory_range;
+
+/* Define a variable to replace the CRASH_MAX_MEMORY_RANGES macro */
+static int crash_max_memory_ranges;
+
+/*
+ * Used to save various memory ranges/regions needed for the captured
+ * kernel to boot. (lime memmap= option in other archs)
+ */
+mem_rgns_t usablemem_rgns = {0, NULL};
+
+/*
+ * To store the memory size of the first kernel and this value will be
+ * passed to the second kernel as command line (savemaxmem=xM).
+ * The second kernel will be calculated saved_max_pfn based on this
+ * variable.
+ * Since we are creating/using usable-memory property, there is no way
+ * we can determine the RAM size unless parsing the device-tree/memoy@/reg
+ * property in the kernel.
+ */
+unsigned long long saved_max_mem;
+
+/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
+ * create Elf headers. Keeping it separate from get_memory_ranges() as
+ * requirements are different in the case of normal kexec and crashdumps.
+ *
+ * Normal kexec needs to look at all of available physical memory irrespective
+ * of the fact how much of it is being used by currently running kernel.
+ * Crashdumps need to have access to memory regions actually being used by
+ * running  kernel. Expecting a different file/data structure than /proc/iomem
+ * to look into down the line. May be something like /proc/kernelmem or may
+ * be zone data structures exported from kernel.
+ */
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+{
+
+	int memory_ranges = 0;
+	char device_tree[256] = "/proc/device-tree/";
+	char fname[256];
+	char buf[MAXBYTES-1];
+	DIR *dir, *dmem;
+	FILE *file;
+	struct dirent *dentry, *mentry;
+	int i, n, crash_rng_len = 0;
+	unsigned long long start, end, cstart, cend;
+
+	crash_max_memory_ranges = max_memory_ranges + 6;
+	crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges;
+
+	crash_memory_range = (struct memory_range *) malloc(crash_rng_len);
+	if (!crash_memory_range) {
+		fprintf(stderr, "Allocation for crash memory range failed\n");
+		return -1;
+	}
+	memset(crash_memory_range, 0, crash_rng_len);
+
+	/* create a separate program header for the backup region */
+	crash_memory_range[0].start = BACKUP_SRC_START;
+	crash_memory_range[0].end = BACKUP_SRC_END + 1;
+	crash_memory_range[0].type = RANGE_RAM;
+	memory_ranges++;
+
+	dir = opendir(device_tree);
+	if (!dir) {
+		perror(device_tree);
+		goto err;
+	}
+	while ((dentry = readdir(dir)) != NULL) {
+		if (strncmp(dentry->d_name, "memory@", 7)
+		    && strcmp(dentry->d_name, "memory"))
+			continue;
+		strcpy(fname, device_tree);
+		strcat(fname, dentry->d_name);
+		dmem = opendir(fname);
+		if (!dmem) {
+			perror(fname);
+			closedir(dir);
+			goto err;
+		}
+		while ((mentry = readdir(dmem)) != NULL) {
+			if (strcmp(mentry->d_name, "reg"))
+				continue;
+			strcat(fname, "/reg");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				closedir(dmem);
+				closedir(dir);
+				goto err;
+			}
+			n = fread(buf, 1, MAXBYTES, file);
+			if (n < 0) {
+				perror(fname);
+				fclose(file);
+				closedir(dmem);
+				closedir(dir);
+				goto err;
+			}
+			if (memory_ranges >= (max_memory_ranges + 1)) {
+				/* No space to insert another element. */
+				fprintf(stderr,
+					"Error: Number of crash memory ranges"
+					" excedeed the max limit\n");
+				goto err;
+			}
+
+			/*
+			 * FIXME: This code fails on platforms that
+			 * have more than one memory range specified
+			 * in the device-tree's /memory/reg property.
+			 * or where the #address-cells and #size-cells
+			 * are not identical.
+			 *
+			 * We should interpret the /memory/reg property
+			 * based on the values of the #address-cells and
+			 * #size-cells properites.
+			 */
+			if (n == (sizeof(unsigned long) * 2)) {
+				start = ((unsigned long *)buf)[0];
+				end = start + ((unsigned long *)buf)[1];
+			} else {
+				start = ((unsigned long long *)buf)[0];
+				end = start + ((unsigned long long *)buf)[1];
+			}
+			if (start == 0 && end >= (BACKUP_SRC_END + 1))
+				start = BACKUP_SRC_END + 1;
+
+			cstart = crash_base;
+			cend = crash_base + crash_size;
+			/*
+			 * Exclude the region that lies within crashkernel
+			 */
+			if (cstart < end && cend > start) {
+				if (start < cstart && end > cend) {
+					crash_memory_range[memory_ranges].start
+						= start;
+					crash_memory_range[memory_ranges].end
+						= cstart;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+					crash_memory_range[memory_ranges].start
+						= cend;
+					crash_memory_range[memory_ranges].end
+						= end;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				} else if (start < cstart) {
+					crash_memory_range[memory_ranges].start
+						= start;
+					crash_memory_range[memory_ranges].end
+						= cstart;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				} else if (end > cend) {
+					crash_memory_range[memory_ranges].start
+						= cend;
+					crash_memory_range[memory_ranges].end
+						= end;
+					crash_memory_range[memory_ranges].type
+						= RANGE_RAM;
+					memory_ranges++;
+				}
+			} else {
+				crash_memory_range[memory_ranges].start = start;
+				crash_memory_range[memory_ranges].end  = end;
+				crash_memory_range[memory_ranges].type
+					= RANGE_RAM;
+				memory_ranges++;
+			}
+			fclose(file);
+		}
+		closedir(dmem);
+	}
+	closedir(dir);
+
+	/*
+	 * If RTAS region is overlapped with crashkernel, need to create ELF
+	 * Program header for the overlapped memory.
+	 */
+	if (crash_base < rtas_base + rtas_size &&
+		rtas_base < crash_base + crash_size) {
+		cstart = rtas_base;
+		cend = rtas_base + rtas_size;
+		if (cstart < crash_base)
+			cstart = crash_base;
+		if (cend > crash_base + crash_size)
+			cend = crash_base + crash_size;
+		crash_memory_range[memory_ranges].start = cstart;
+		crash_memory_range[memory_ranges++].end = cend;
+	}
+	/*
+	 * Can not trust the memory regions order that we read from
+	 * device-tree. Hence, get the MAX end value.
+	 */
+	for (i = 0; i < memory_ranges; i++)
+		if (saved_max_mem < crash_memory_range[i].end)
+			saved_max_mem = crash_memory_range[i].end;
+
+	*range = crash_memory_range;
+	*ranges = memory_ranges;
+#if DEBUG
+	int j;
+	printf("CRASH MEMORY RANGES\n");
+	for (j = 0; j < *ranges; j++) {
+		start = crash_memory_range[j].start;
+		end = crash_memory_range[j].end;
+		fprintf(stderr, "%016Lx-%016Lx\n", start, end);
+	}
+#endif
+	return 0;
+
+err:
+	if (crash_memory_range)
+		free(crash_memory_range);
+	return -1;
+}
+
+/* Converts unsigned long to ascii string. */
+static void ulltoa(unsigned long long i, char *str)
+{
+	int j = 0, k;
+	char tmp;
+
+	do {
+		str[j++] = i % 10 + '0';
+	} while ((i /= 10) > 0);
+	str[j] = '\0';
+
+	/* Reverse the string. */
+	for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
+		tmp = str[k];
+		str[k] = str[j];
+		str[j] = tmp;
+	}
+}
+
+static int add_cmdline_param(char *cmdline, unsigned long long addr,
+				char *cmdstr, char *byte)
+{
+	int cmdlen, len, align = 1024;
+	char str[COMMAND_LINE_SIZE], *ptr;
+
+	/* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/
+	switch (byte[0]) {
+	case 'K':
+		if (addr%align)
+			return -1;
+		addr = addr/align;
+		break;
+	case 'M':
+		addr = addr/(align *align);
+		break;
+	}
+	ptr = str;
+	strcpy(str, cmdstr);
+	ptr += strlen(str);
+	ulltoa(addr, ptr);
+	strcat(str, byte);
+	len = strlen(str);
+	cmdlen = strlen(cmdline) + len;
+	if (cmdlen > (COMMAND_LINE_SIZE - 1))
+		die("Command line overflow\n");
+	strcat(cmdline, str);
+#if DEBUG
+	fprintf(stderr, "Command line after adding elfcorehdr: %s\n", cmdline);
+#endif
+	return 0;
+}
+
+/* Loads additional segments in case of a panic kernel is being loaded.
+ * One segment for backup region, another segment for storing elf headers
+ * for crash memory image.
+ */
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base)
+{
+	void *tmp;
+	unsigned long sz, elfcorehdr;
+	int nr_ranges, align = 1024, i;
+	unsigned long long end;
+	struct memory_range *mem_range;
+
+	if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+		return -1;
+
+	/* Create a backup region segment to store backup data*/
+	sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
+	tmp = xmalloc(sz);
+	memset(tmp, 0, sz);
+	info->backup_start = add_buffer(info, tmp, sz, sz, align,
+					0, max_addr, 1);
+	reserve(info->backup_start, sz);
+
+	/* On powerpc memory ranges in device-tree is denoted as start
+	 * and size rather than start and end, as is the case with
+	 * other architectures like i386 . Because of this when loading
+	 * the memory ranges in crashdump-elf.c the filesz calculation
+	 * [ end - start + 1 ] goes for a toss.
+	 *
+	 * To be in sync with other archs adjust the end value for
+	 * every crash memory range before calling the generic function
+	 */
+
+	for (i = 0; i < nr_ranges; i++) {
+		end = crash_memory_range[i].end - 1;
+		crash_memory_range[i].end = end;
+	}
+
+
+#ifdef CONFIG_PPC64
+	/* Create elf header segment and store crash image data. */
+	if (arch_options.core_header_type == CORE_TYPE_ELF64) {
+		if (crash_create_elf64_headers(info, &elf_info64,
+					crash_memory_range, nr_ranges, &tmp,
+					&sz, ELF_CORE_HEADER_ALIGN) < 0)
+			return -1;
+	} else if (crash_create_elf32_headers(info, &elf_info32,
+				crash_memory_range, nr_ranges, &tmp, &sz,
+				ELF_CORE_HEADER_ALIGN) < 0)
+			return -1;
+#else
+	if (crash_create_elf32_headers(info, &elf_info32, crash_memory_range,
+				nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN)
+			< 0)
+		return -1;
+#endif
+
+	elfcorehdr = add_buffer(info, tmp, sz, sz, align,
+			min_base, max_addr, 1);
+	reserve(elfcorehdr, sz);
+	/* modify and store the cmdline in a global array. This is later
+	 * read by flatten_device_tree and modified if required
+	 */
+	add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K");
+	add_cmdline_param(mod_cmdline, saved_max_mem, " savemaxmem=", "M");
+	return 0;
+}
+
+/*
+ * Used to save various memory regions needed for the captured kernel.
+ */
+
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size)
+{
+	int i;
+	unsigned long long end = base + size;
+	unsigned long long ustart, uend;
+
+	base = _ALIGN_DOWN(base, getpagesize());
+	end = _ALIGN_UP(end, getpagesize());
+
+	for (i = 0; i < usablemem_rgns.size; i++) {
+		ustart = usablemem_rgns.ranges[i].start;
+		uend = usablemem_rgns.ranges[i].end;
+		if (base < uend && end > ustart) {
+			if ((base >= ustart) && (end <= uend))
+				return;
+			if (base < ustart && end > uend) {
+				usablemem_rgns.ranges[i].start = base;
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			} else if (base < ustart) {
+				usablemem_rgns.ranges[i].start = base;
+				return;
+			} else if (end > uend) {
+				usablemem_rgns.ranges[i].end = end;
+				return;
+			}
+		}
+	}
+	usablemem_rgns.ranges[usablemem_rgns.size].start = base;
+	usablemem_rgns.ranges[usablemem_rgns.size++].end = end;
+
+#ifdef DEBUG
+	fprintf(stderr, "usable memory rgns size:%u base:%llx size:%llx\n",
+		usablemem_rgns.size, base, size);
+#endif
+}
+
+int is_crashkernel_mem_reserved(void)
+{
+	int fd;
+
+	fd = open("/proc/device-tree/chosen/linux,crashkernel-base", O_RDONLY);
+	if (fd < 0)
+		return 0;
+	close(fd);
+	return 1;
+}
+
diff --git a/kexec/arch/ppc/crashdump-powerpc.h b/kexec/arch/ppc/crashdump-powerpc.h
new file mode 100644
index 0000000..dc2772d
--- /dev/null
+++ b/kexec/arch/ppc/crashdump-powerpc.h
@@ -0,0 +1,38 @@
+#ifndef CRASHDUMP_POWERPC_H
+#define CRASHDUMP_POWERPC_H
+
+struct kexec_info;
+int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
+				unsigned long max_addr, unsigned long min_base);
+void add_usable_mem_rgns(unsigned long long base, unsigned long long size);
+
+extern struct arch_options_t arch_options;
+
+#ifdef CONFIG_PPC64
+#define PAGE_OFFSET	0xC000000000000000UL
+#define VMALLOCBASE	0xD000000000000000UL
+#define MAXMEM		(-KERNELBASE-VMALLOCBASE)
+#else
+#define PAGE_OFFSET	0xC0000000
+#define MAXMEM		0x30000000 /* Use CONFIG_LOWMEM_SIZE from kernel */
+#endif
+
+#define KERNELBASE	PAGE_OFFSET
+#define __pa(x)		((unsigned long)(x)-PAGE_OFFSET)
+
+#define COMMAND_LINE_SIZE	512 /* from kernel */
+/* Backup Region, First 64K of System RAM. */
+#define BACKUP_SRC_START	0x0000
+#define BACKUP_SRC_END		0xffff
+#define BACKUP_SRC_SIZE		(BACKUP_SRC_END - BACKUP_SRC_START + 1)
+
+#define KDUMP_BACKUP_LIMIT	BACKUP_SRC_SIZE
+#define _ALIGN_UP(addr, size)	(((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr, size)	((addr)&(~((size)-1)))
+
+extern unsigned long long crash_base;
+extern unsigned long long crash_size;
+extern unsigned int rtas_base;
+extern unsigned int rtas_size;
+
+#endif /* CRASHDUMP_POWERPC_H */
diff --git a/kexec/arch/ppc/fs2dt.c b/kexec/arch/ppc/fs2dt.c
new file mode 100644
index 0000000..238a3f2
--- /dev/null
+++ b/kexec/arch/ppc/fs2dt.c
@@ -0,0 +1,460 @@
+/*
+ * fs2dt: creates a flattened device-tree
+ *
+ * Copyright (C) 2004,2005  Milton D Miller II, IBM Corporation
+ * Copyright (C) 2005  R Sharada (sharada@in.ibm.com), IBM Corporation
+ *
+ * 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 (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "../../kexec.h"
+#include "kexec-ppc.h"
+
+#define MAXPATH			1024	/* max path name length */
+#define NAMESPACE		16384	/* max bytes for property names */
+#define TREEWORDS		65536	/* max 32 bit words for properties */
+#define MEMRESERVE		256	/* max number of reserved memory blks */
+#define MAX_MEMORY_RANGES	1024
+#define COMMAND_LINE_SIZE	512	/* from kernel */
+
+static char pathname[MAXPATH];
+static char propnames[NAMESPACE] = { 0 };
+static unsigned dtstruct[TREEWORDS], *dt;
+static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 };
+
+static int crash_param;
+static char local_cmdline[COMMAND_LINE_SIZE] = { "" };
+static unsigned *dt_len; /* changed len of modified cmdline
+			    in flat device-tree */
+static struct bootblock bb[1];
+
+void reserve(unsigned long long where, unsigned long long length)
+{
+	size_t offset;
+
+	for (offset = 0; mem_rsrv[offset + 1]; offset += 2)
+		;
+
+	if (offset + 4 >= 2 * MEMRESERVE)
+		die("unrecoverable error: exhasuted reservation meta data\n");
+
+	mem_rsrv[offset] = where;
+	mem_rsrv[offset + 1] = length;
+	mem_rsrv[offset + 3] = 0;  /* N.B: don't care about offset + 2 */
+}
+
+/* look for properties we need to reserve memory space for */
+static void checkprop(char *name, unsigned *data, int len)
+{
+	static unsigned long long base, size, end;
+
+	if ((data == NULL) && (base || size || end))
+		die("unrecoverable error: no property data");
+	else if (!strcmp(name, "linux,rtas-base"))
+		base = *data;
+	else if (!strcmp(name, "linux,tce-base"))
+		base = *(unsigned long long *) data;
+	else if (!strcmp(name, "rtas-size") ||
+			!strcmp(name, "linux,tce-size"))
+		size = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-start"))
+		if (len == 8)
+			base = *(unsigned long long *) data;
+		else
+			base = *data;
+	else if (reuse_initrd && !strcmp(name, "linux,initrd-end"))
+		end = *(unsigned long long *) data;
+
+	if (size && end)
+		die("unrecoverable error: size and end set at same time\n");
+	if (base && size) {
+		reserve(base, size);
+		base = 0;
+		size = 0;
+	}
+	if (base && end) {
+		reserve(base, end-base);
+		base = 0;
+		end = 0;
+	}
+}
+
+/*
+ * return the property index for a property name, creating a new one
+ * if needed.
+ */
+static unsigned propnum(const char *name)
+{
+	unsigned offset = 0;
+
+	while (propnames[offset])
+		if (strcmp(name, propnames+offset))
+			offset += strlen(propnames+offset)+1;
+		else
+			return offset;
+
+	if (NAMESPACE - offset < strlen(name) + 1)
+		die("unrecoverable error: propnames overrun\n");
+
+	strcpy(propnames+offset, name);
+
+	return offset;
+}
+
+static void add_usable_mem_property(int fd, int len)
+{
+	char fname[MAXPATH], *bname;
+	unsigned long buf[2];
+	unsigned long ranges[2*MAX_MEMORY_RANGES];
+	unsigned long long base, end, loc_base, loc_end;
+	int range, rlen = 0;
+
+	strcpy(fname, pathname);
+	bname = strrchr(fname, '/');
+	bname[0] = '\0';
+	bname = strrchr(fname, '/');
+	if (strncmp(bname, "/memory@", 8) && strcmp(bname, "/memory"))
+		return;
+
+	if (len < 2 * sizeof(unsigned long))
+		die("unrecoverable error: not enough data for mem property\n");
+	len = 2 * sizeof(unsigned long);
+
+	if (lseek(fd, 0, SEEK_SET) < 0)
+		die("unrecoverable error: error seeking in \"%s\": %s\n",
+		    pathname, strerror(errno));
+	if (read(fd, buf, len) != len)
+		die("unrecoverable error: error reading \"%s\": %s\n",
+		    pathname, strerror(errno));
+
+	if (~0ULL - buf[0] < buf[1])
+		die("unrecoverable error: mem property overflow\n");
+	base = buf[0];
+	end = base + buf[1];
+
+	for (range = 0; range < usablemem_rgns.size; range++) {
+		loc_base = usablemem_rgns.ranges[range].start;
+		loc_end = usablemem_rgns.ranges[range].end;
+		if (loc_base >= base && loc_end <= end) {
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		} else if (base < loc_end && end > loc_base) {
+			if (loc_base < base)
+				loc_base = base;
+			if (loc_end > end)
+				loc_end = end;
+			ranges[rlen++] = loc_base;
+			ranges[rlen++] = loc_end - loc_base;
+		}
+	}
+
+	if (!rlen) {
+		/*
+		 * User did not pass any ranges for thsi region. Hence, write
+		 * (0,0) duple in linux,usable-memory property such that
+		 * this region will be ignored.
+		 */
+		ranges[rlen++] = 0;
+		ranges[rlen++] = 0;
+	}
+
+	rlen = rlen * sizeof(unsigned long);
+	/*
+	 * No add linux,usable-memory property.
+	 */
+	*dt++ = 3;
+	*dt++ = rlen;
+	*dt++ = propnum("linux,usable-memory");
+	memcpy(dt, &ranges, rlen);
+	dt += (rlen + 3)/4;
+}
+
+/* put all properties (files) in the property structure */
+static void putprops(char *fn, struct dirent **nlist, int numlist)
+{
+	struct dirent *dp;
+	int i = 0, fd, len;
+	struct stat statbuf;
+
+	for (i = 0; i < numlist; i++) {
+		dp = nlist[i];
+		strcpy(fn, dp->d_name);
+
+		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+			continue;
+
+		if (lstat(pathname, &statbuf))
+			die("unrecoverable error: could not stat \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (!crash_param && !strcmp(fn, "linux,crashkernel-base"))
+			continue;
+
+		if (!crash_param && !strcmp(fn, "linux,crashkernel-size"))
+			continue;
+
+		/*
+		 * This property will be created for each node during kexec
+		 * boot. So, ignore it.
+		 */
+		if (!strcmp(dp->d_name, "linux,pci-domain") ||
+			!strcmp(dp->d_name, "linux,htab-base") ||
+			!strcmp(dp->d_name, "linux,htab-size") ||
+			!strcmp(dp->d_name, "linux,kernel-end") ||
+			!strcmp(dp->d_name, "linux,usable-memory"))
+				continue;
+
+		/* This property will be created/modified later in putnode()
+		 * So ignore it, unless we are reusing the initrd.
+		 */
+		if ((!strcmp(dp->d_name, "linux,initrd-start") ||
+		     !strcmp(dp->d_name, "linux,initrd-end")) &&
+		    !reuse_initrd)
+				continue;
+
+		if (!S_ISREG(statbuf.st_mode))
+			continue;
+
+		len = statbuf.st_size;
+
+		*dt++ = 3;
+		dt_len = dt;
+		*dt++ = len;
+		*dt++ = propnum(fn);
+
+		fd = open(pathname, O_RDONLY);
+		if (fd == -1)
+			die("unrecoverable error: could not open \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (read(fd, dt, len) != len)
+			die("unrecoverable error: could not read \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		checkprop(fn, dt, len);
+
+		/* Get the cmdline from the device-tree and modify it */
+		if (!strcmp(dp->d_name, "bootargs")) {
+			int cmd_len;
+			char temp_cmdline[COMMAND_LINE_SIZE] = { "" };
+			char *param = NULL;
+			cmd_len = strlen(local_cmdline);
+			if (cmd_len != 0) {
+				param = strstr(local_cmdline, "crashkernel=");
+				if (param)
+					crash_param = 1;
+				param = strstr(local_cmdline, "root=");
+			}
+			if (!param) {
+				char *old_param;
+				memcpy(temp_cmdline, dt, len);
+				param = strstr(temp_cmdline, "root=");
+				if (param) {
+					old_param = strtok(param, " ");
+					if (cmd_len != 0)
+						strcat(local_cmdline, " ");
+					strcat(local_cmdline, old_param);
+				}
+			}
+			strcat(local_cmdline, " ");
+			cmd_len = strlen(local_cmdline);
+			cmd_len = cmd_len + 1;
+			memcpy(dt, local_cmdline, cmd_len);
+			len = cmd_len;
+			*dt_len = cmd_len;
+#if	DEBUG
+			fprintf(stderr, "Modified cmdline:%s\n", local_cmdline);
+#endif
+		}
+
+		dt += (len + 3)/4;
+		if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size)
+			add_usable_mem_property(fd, len);
+		close(fd);
+	}
+
+	fn[0] = '\0';
+	checkprop(pathname, NULL, 0);
+}
+
+/*
+ * Compare function used to sort the device-tree directories
+ * This function will be passed to scandir.
+ */
+static int comparefunc(const void *dentry1, const void *dentry2)
+{
+	char *str1 = (*(struct dirent **)dentry1)->d_name;
+	char *str2 = (*(struct dirent **)dentry2)->d_name;
+
+	/*
+	 * strcmp scans from left to right and fails to idetify for some
+	 * strings such as memory@10000000 and memory@f000000.
+	 * Therefore, we get the wrong sorted order like memory@10000000 and
+	 * memory@f000000.
+	 */
+	if (strchr(str1, '@') && strchr(str2, '@') &&
+		(strlen(str1) > strlen(str2)))
+		return 1;
+
+	return strcmp(str1, str2);
+}
+
+/*
+ * put a node (directory) in the property structure.  first properties
+ * then children.
+ */
+static void putnode(void)
+{
+	char *dn;
+	struct dirent *dp;
+	char *basename;
+	struct dirent **namelist;
+	int numlist, i;
+	struct stat statbuf;
+
+	numlist = scandir(pathname, &namelist, 0, comparefunc);
+	if (numlist < 0)
+		die("unrecoverable error: could not scan \"%s\": %s\n",
+		    pathname, strerror(errno));
+	if (numlist == 0)
+		die("unrecoverable error: no directory entries in \"%s\"",
+		    pathname);
+
+	basename = strrchr(pathname, '/') + 1;
+
+	*dt++ = 1;
+	strcpy((void *)dt, *basename ? basename : "");
+	dt += strlen((void *)dt) / sizeof(unsigned) + 1;
+
+	strcat(pathname, "/");
+	dn = pathname + strlen(pathname);
+
+	putprops(dn, namelist, numlist);
+
+	/* Add initrd entries to the second kernel */
+	if (initrd_base && !strcmp(basename, "chosen/")) {
+		int len = 8;
+		unsigned long long initrd_end;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-start");
+
+		memcpy(dt, &initrd_base, len);
+		dt += (len + 3)/4;
+
+		len = 8;
+		*dt++ = 3;
+		*dt++ = len;
+		*dt++ = propnum("linux,initrd-end");
+
+		initrd_end = initrd_base + initrd_size;
+
+		memcpy(dt, &initrd_end, len);
+		dt += (len + 3)/4;
+
+		reserve(initrd_base, initrd_size);
+	}
+
+	for (i = 0; i < numlist; i++) {
+		dp = namelist[i];
+		strcpy(dn, dp->d_name);
+		free(namelist[i]);
+
+		if (!strcmp(dn, ".") || !strcmp(dn, ".."))
+			continue;
+
+		if (lstat(pathname, &statbuf))
+			die("unrecoverable error: could not stat \"%s\": %s\n",
+			    pathname, strerror(errno));
+
+		if (S_ISDIR(statbuf.st_mode))
+			putnode();
+	}
+
+	*dt++ = 2;
+	dn[-1] = '\0';
+	free(namelist);
+}
+
+int create_flatten_tree(struct kexec_info *info, unsigned char **bufp,
+			unsigned long *sizep, char *cmdline)
+{
+	unsigned long len;
+	unsigned long tlen;
+	unsigned char *buf;
+	unsigned long me;
+
+	me = 0;
+
+	strcpy(pathname, "/proc/device-tree/");
+
+	dt = dtstruct;
+
+	if (cmdline)
+		strcpy(local_cmdline, cmdline);
+
+	putnode();
+	*dt++ = 9;
+
+	len = sizeof(bb[0]);
+	len += 7; len &= ~7;
+
+	bb->off_mem_rsvmap = len;
+
+	for (len = 1; mem_rsrv[len]; len += 2)
+		;
+	len += 3;
+	len *= sizeof(mem_rsrv[0]);
+
+	bb->off_dt_struct = bb->off_mem_rsvmap + len;
+
+	len = dt - dtstruct;
+	len *= sizeof(unsigned);
+	bb->dt_struct_size = len;
+	bb->off_dt_strings = bb->off_dt_struct + len;
+
+	len = propnum("");
+	bb->dt_strings_size = len;
+	len +=  3; len &= ~3;
+	bb->totalsize = bb->off_dt_strings + len;
+
+	bb->magic = 0xd00dfeed;
+	bb->version = 17;
+	bb->last_comp_version = 16;
+
+	reserve(me, bb->totalsize); /* patched later in kexec_load */
+
+	buf = (unsigned char *) malloc(bb->totalsize);
+	*bufp = buf;
+	memcpy(buf, bb, bb->off_mem_rsvmap);
+	tlen = bb->off_mem_rsvmap;
+	memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap);
+	tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap);
+	memcpy(buf+tlen, dtstruct,  bb->off_dt_strings - bb->off_dt_struct);
+	tlen = tlen +  (bb->off_dt_strings - bb->off_dt_struct);
+	memcpy(buf+tlen, propnames,  bb->totalsize - bb->off_dt_strings);
+	tlen = tlen + bb->totalsize - bb->off_dt_strings;
+	*sizep = tlen;
+	return 0;
+}
diff --git a/kexec/arch/ppc/kexec-elf-ppc.c b/kexec/arch/ppc/kexec-elf-ppc.c
index a54a5d5..4bcac26 100644
--- a/kexec/arch/ppc/kexec-elf-ppc.c
+++ b/kexec/arch/ppc/kexec-elf-ppc.c
@@ -11,6 +11,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -23,15 +24,22 @@
 #include "../../kexec-elf.h"
 #include "kexec-ppc.h"
 #include <arch/options.h>
+#include "../../kexec-syscall.h"
+#include "crashdump-powerpc.h"
 
 #include "config.h"
 #include "fixup_dtb.h"
 
 static const int probe_debug = 0;
 
-#define MAX_COMMAND_LINE   256
+unsigned long long initrd_base, initrd_size;
+unsigned char reuse_initrd;
+const char *ramdisk;
+int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *,
+			char *);
 
 #define UPSZ(X) ((sizeof(X) + 3) & ~3)
+#ifdef WITH_GAMECUBE
 static struct boot_notes {
 	Elf_Bhdr hdr;
 	Elf_Nhdr bl_hdr;
@@ -65,7 +73,7 @@ static struct boot_notes {
 		.n_type = EBN_COMMAND_LINE,
 	},
 };
-
+#endif
 
 int elf_ppc_probe(const char *buf, off_t len)
 {
@@ -92,6 +100,7 @@ int elf_ppc_probe(const char *buf, off_t len)
 	return result;
 }
 
+#ifdef WITH_GAMECUBE
 static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 {
 	struct mem_phdr *phdr, *phdr_end;
@@ -112,6 +121,7 @@ static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 		phdr->p_paddr &= ~0xf0000000;	/* clear bits 0-3, ibm syntax */
 	}
 }
+#endif
 
 #define OPT_APPEND	(OPT_ARCH_MAX+0)
 #define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
@@ -145,10 +155,24 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 	struct kexec_info *info)
 {
 	struct mem_ehdr ehdr;
-	char *command_line;
+	char *command_line, *crash_cmdline, *cmdline_buf;
 	int command_line_len;
 	char *dtb;
 	int result;
+	unsigned long max_addr, hole_addr;
+	struct mem_phdr *phdr;
+	size_t size;
+	unsigned long long *rsvmap_ptr;
+	struct bootblock *bb_ptr;
+	unsigned int nr_segments;
+	unsigned long my_kernel, my_dt_offset;
+	unsigned long my_stack, my_backup_start;
+#ifdef CONFIG_PPC64
+	unsigned long toc_addr;
+#endif
+	unsigned int slave_code[256 / sizeof(unsigned int)], master_entry;
+	unsigned char *seg_buf = NULL;
+	off_t seg_size = 0;
 #ifdef WITH_GAMECUBE
 	int target_is_gamecube = 1;
 	char *arg_buf;
@@ -170,6 +194,9 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 
 	command_line = NULL;
 	dtb = NULL;
+	max_addr = LONG_MAX;
+	hole_addr = 0;
+
 	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch (opt) {
 		default:
@@ -209,15 +236,45 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 
 	fixup_nodes[cur_fixup] = NULL;
 
+	/* Need to append some command line parameters internally in case of
+	 * taking crash dumps.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		crash_cmdline = xmalloc(COMMAND_LINE_SIZE);
+		memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE);
+	} else
+		crash_cmdline = NULL;
+
 	/* Parse the Elf file */
 	result = build_elf_exec_info(buf, len, &ehdr, 0);
 	if (result < 0) {
 		free_elf_info(&ehdr);
 		return result;
 	}
+
+#ifdef WITH_GAMECUBE
 	if (target_is_gamecube) {
 		gamecube_hack_addresses(&ehdr);
 	}
+#endif
+
+	/* Load the Elf data. Physical load addresses in elf64 header do not
+	 * show up correctly. Use user supplied address for now to patch the
+	 * elf header
+	 */
+
+	phdr = &ehdr.e_phdr[0];
+	size = phdr->p_filesz;
+	if (size > phdr->p_memsz)
+		size = phdr->p_memsz;
+
+	hole_addr = locate_hole(info, size, 0, 0, max_addr, 1);
+#ifdef CONFIG_PPC64
+	ehdr.e_phdr[0].p_paddr = (Elf64_Addr)hole_addr;
+#else
+	ehdr.e_phdr[0].p_paddr = hole_addr;
+#endif
+
 	/* Load the Elf data */
 	result = elf_exec_load(&ehdr, info);
 	if (result < 0) {
@@ -225,6 +282,27 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		return result;
 	}
 
+	/* If panic kernel is being loaded, additional segments need
+	 * to be created.
+	 */
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		result = load_crashdump_segments(info, crash_cmdline,
+						max_addr, 0);
+		if (result < 0) {
+			free(crash_cmdline);
+			return -1;
+		}
+	}
+
+	cmdline_buf = xmalloc(COMMAND_LINE_SIZE);
+	memset((void *)cmdline_buf, 0, COMMAND_LINE_SIZE);
+	if (command_line)
+		strncat(cmdline_buf, command_line, command_line_len);
+	if (crash_cmdline)
+		strncat(cmdline_buf, crash_cmdline,
+				sizeof(crash_cmdline) -
+				strlen(crash_cmdline) - 1);
+
 	/*
 	 * In case of a toy we take the hardcoded things and an easy setup via
 	 * one of the assembly startups. Every thing else should be grown up
@@ -269,31 +347,105 @@ int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len,
 		blob_buf = slurp_file(dtb, &blob_size);
 		if (!blob_buf || !blob_size)
 			die("Device tree seems to be an empty file.\n");
-		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, command_line);
+		blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes,
+				cmdline_buf);
 		dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
 				KERNEL_ACCESS_TOP, -1);
 	} else {
-		dtb_addr = 0;
+		/* create from fs2dt */
+		seg_buf = NULL;
+		seg_size = 0;
+		create_flatten_tree(info, (unsigned char **)&seg_buf,
+				(unsigned long *)&seg_size, cmdline_buf);
+		add_buffer(info, seg_buf, seg_size, seg_size,
+#ifdef CONFIG_PPC64
+				0, 0,  max_addr, -1);
+#else
+		/* load dev tree at 16 Mb offset from kernel load address */
+			0, 0, ehdr.e_phdr[0].p_paddr + SIZE_16M, -1);
+#endif
 	}
 
-	/* set various variables for the purgatory */
-	addr = ehdr.e_entry;
-	elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
 
-	addr = dtb_addr;
-	elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
+	if (dtb) {
+		/* set various variables for the purgatory */
+		addr = ehdr.e_entry;
+		elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
+
+		addr = dtb_addr;
+		elf_rel_set_symbol(&info->rhdr, "dt_offset",
+						&addr, sizeof(addr));
 
-	addr = rmo_top;
-	elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
+		addr = rmo_top;
+
+		elf_rel_set_symbol(&info->rhdr, "mem_size",
+						&addr, sizeof(addr));
 
 #define PUL_STACK_SIZE	(16 * 1024)
-	addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1);
-	addr += PUL_STACK_SIZE;
-	elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
+		addr = locate_hole(info, PUL_STACK_SIZE, 0, 0,
+				elf_max_addr(&ehdr), 1);
+		addr += PUL_STACK_SIZE;
+		elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr));
 #undef PUL_STACK_SIZE
 
-	addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
-	info->entry = (void *)addr;
+		addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
+		info->entry = (void *)addr;
+
+	} else { /*from fs2dt*/
+
+		/* patch reserve map address for flattened device-tree
+		 * find last entry (both 0) in the reserve mem list.  Assume DT
+		 * entry is before this one
+		 */
+		bb_ptr = (struct bootblock *)(
+			(unsigned char *)info->segment[(info->nr_segments) -
+				1].buf);
+		rsvmap_ptr = (unsigned long long *)(
+			(unsigned char *)info->segment[(info->nr_segments) -
+				1].buf + bb_ptr->off_mem_rsvmap);
+		while (*rsvmap_ptr || *(rsvmap_ptr + 1))
+			rsvmap_ptr += 2;
+		rsvmap_ptr -= 2;
+		*rsvmap_ptr = (unsigned long)(
+				info->segment[(info->nr_segments)-1].mem);
+		rsvmap_ptr++;
+		*rsvmap_ptr = (unsigned long long)bb_ptr->totalsize;
+
+		nr_segments = info->nr_segments;
+
+		/* Set kernel */
+		my_kernel = (unsigned long)info->segment[0].mem;
+		elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel,
+				sizeof(my_kernel));
+
+		/* Set dt_offset */
+		my_dt_offset = (unsigned long)info->segment[nr_segments -
+			1].mem;
+		elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset,
+				sizeof(my_dt_offset));
+
+		/* get slave code from new kernel, put in purgatory */
+		elf_rel_get_symbol(&info->rhdr, "purgatory_start", slave_code,
+				sizeof(slave_code));
+		master_entry = slave_code[0];
+		memcpy(slave_code, info->segment[0].buf, sizeof(slave_code));
+		slave_code[0] = master_entry;
+		elf_rel_set_symbol(&info->rhdr, "purgatory_start", slave_code,
+				sizeof(slave_code));
+
+		/* Set stack address */
+		my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1);
+		my_stack += 16*1024;
+		elf_rel_set_symbol(&info->rhdr, "stack", &my_stack,
+				sizeof(my_stack));
+	}
+
+	if (info->kexec_flags & KEXEC_ON_CRASH) {
+		/* Set backup address */
+		my_backup_start = info->backup_start;
+		elf_rel_set_symbol(&info->rhdr, "backup_start",
+				&my_backup_start, sizeof(my_backup_start));
+	}
 #endif
 	return 0;
 }
diff --git a/kexec/arch/ppc/kexec-ppc.c b/kexec/arch/ppc/kexec-ppc.c
index f552d79..aabc02f 100644
--- a/kexec/arch/ppc/kexec-ppc.c
+++ b/kexec/arch/ppc/kexec-ppc.c
@@ -21,6 +21,7 @@
 #include "../../kexec.h"
 #include "../../kexec-syscall.h"
 #include "kexec-ppc.h"
+#include "crashdump-powerpc.h"
 #include <arch/options.h>
 
 #include "config.h"
@@ -45,13 +46,14 @@ static int get_memory_ranges_gc(struct memory_range **range, int *ranges,
 }
 #else
 static int use_new_dtb;
-static int max_memory_ranges;
+int max_memory_ranges;
 static int nr_memory_ranges, nr_exclude_ranges;
 static struct memory_range *exclude_range;
 static struct memory_range *memory_range;
 static struct memory_range *base_memory_range;
 static uint64_t memory_max;
 uint64_t rmo_top;
+unsigned long long crash_base, crash_size;
 unsigned int rtas_base, rtas_size;
 
 /*
@@ -174,7 +176,40 @@ static int sort_base_ranges(void)
 
 #define MAXBYTES 128
 
-/* Get base memory ranges */
+static int realloc_memory_ranges(void)
+{
+	size_t memory_range_len;
+
+	max_memory_ranges++;
+	memory_range_len = sizeof(struct memory_range) * max_memory_ranges;
+
+	memory_range = (struct memory_range *) malloc(memory_range_len);
+	if (!memory_range)
+		goto err;
+
+	base_memory_range = (struct memory_range *) realloc(memory_range,
+			memory_range_len);
+	if (!base_memory_range)
+		goto err;
+
+	exclude_range = (struct memory_range *) realloc(exclude_range,
+			memory_range_len);
+	if (!exclude_range)
+		goto err;
+
+	usablemem_rgns.ranges = (struct memory_range *)
+				realloc(usablemem_rgns.ranges,
+						memory_range_len);
+	if (!(usablemem_rgns.ranges))
+		goto err;
+
+	return 0;
+
+err:
+	fprintf(stderr, "memory range structure re-allocation failure\n");
+	return -1;
+}
+
 static int get_base_ranges(void)
 {
 	int local_memory_ranges = 0;
@@ -219,8 +254,10 @@ static int get_base_ranges(void)
 				return -1;
 			}
 			if (local_memory_ranges >= max_memory_ranges) {
-				fclose(file);
-				break;
+				if (realloc_memory_ranges() < 0){
+	-				fclose(file);
+					break;
+				}
 			}
 			base_memory_range[local_memory_ranges].start =
 				((uint32_t *)buf)[0];
@@ -250,16 +287,23 @@ static int get_base_ranges(void)
 /* Get devtree details and create exclude_range array
  * Also create usablemem_ranges for KEXEC_ON_CRASH
  */
-static int get_devtree_details(unsigned long UNUSED(kexec_flags))
+static int get_devtree_details(unsigned long kexec_flags)
 {
 	uint64_t rmo_base;
-	char buf[MAXBYTES];
+	unsigned long long tce_base;
+	unsigned int tce_size;
+	unsigned long long htab_base, htab_size;
+	unsigned long long kernel_end;
+	unsigned long long initrd_start, initrd_end;
+	char buf[MAXBYTES-1];
 	char device_tree[256] = "/proc/device-tree/";
 	char fname[256];
 	DIR *dir, *cdir;
 	FILE *file;
 	struct dirent *dentry;
+	struct stat fstat;
 	int n, i = 0;
+	unsigned long tmp_long;
 
 	if ((dir = opendir(device_tree)) == NULL) {
 		perror(device_tree);
@@ -269,10 +313,10 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 	while ((dentry = readdir(dir)) != NULL) {
 		if (strncmp(dentry->d_name, "chosen", 6) &&
 				strncmp(dentry->d_name, "memory@", 7) &&
-				strcmp(dentry->d_name, "memory") &&
+				strncmp(dentry->d_name, "memory", 6) &&
+				strncmp(dentry->d_name, "pci@", 4) &&
 				strncmp(dentry->d_name, "rtas", 4))
 			continue;
-
 		strcpy(fname, device_tree);
 		strcat(fname, dentry->d_name);
 		if ((cdir = opendir(fname)) == NULL) {
@@ -280,13 +324,172 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			goto error_opendir;
 		}
 
+		if (strncmp(dentry->d_name, "chosen", 6) == 0) {
+			strcat(fname, "/linux,kernel-end");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&tmp_long, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			kernel_end = tmp_long;
+			fclose(file);
+
+			/* Add kernel memory to exclude_range */
+			exclude_range[i].start = 0x0UL;
+			exclude_range[i].end = kernel_end;
+			i++;
+			if (i >= max_memory_ranges)
+				realloc_memory_ranges();
+			if (kexec_flags & KEXEC_ON_CRASH) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-base");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				if (fread(&tmp_long, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				crash_base = tmp_long;
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,crashkernel-size");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				if (fread(&tmp_long, sizeof(unsigned long), 1,
+						file) != 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				crash_size = tmp_long;
+
+				if (crash_base > mem_min)
+					mem_min = crash_base;
+				if (crash_base + crash_size < mem_max)
+					mem_max = crash_base + crash_size;
+
+				add_usable_mem_rgns(0, crash_base + crash_size);
+				reserve(KDUMP_BACKUP_LIMIT,
+						crash_base-KDUMP_BACKUP_LIMIT);
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-base");
+			file = fopen(fname, "r");
+			if (!file) {
+				closedir(cdir);
+				if (errno == ENOENT) {
+					/* Non LPAR */
+					errno = 0;
+					continue;
+				}
+				perror(fname);
+				goto error_opendir;
+			}
+			if (fread(&htab_base, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,htab-size");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&htab_size, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			/* Add htab address to exclude_range - NON-LPAR only */
+			exclude_range[i].start = htab_base;
+			exclude_range[i].end = htab_base + htab_size;
+			i++;
+			if (i >= max_memory_ranges)
+				realloc_memory_ranges();
+
+			/* reserve the initrd_start and end locations. */
+			if (reuse_initrd) {
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-start");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, &fstat) != 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (fread(&initrd_start, fstat.st_size, 1, file)
+						!= 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				fclose(file);
+
+				memset(fname, 0, sizeof(fname));
+				strcpy(fname, device_tree);
+				strcat(fname, dentry->d_name);
+				strcat(fname, "/linux,initrd-end");
+				file = fopen(fname, "r");
+				if (!file) {
+					perror(fname);
+					goto error_opencdir;
+				}
+				/* check for 4 and 8 byte initrd offset sizes */
+				if (stat(fname, &fstat) != 0) {
+					perror(fname);
+					goto error_openfile;
+				}
+				if (fread(&initrd_end, fstat.st_size, 1, file)
+						!= 1) {
+					perror(fname);
+					goto error_openfile;
+				}
+				fclose(file);
+
+				/* Add initrd address to exclude_range */
+				exclude_range[i].start = initrd_start;
+				exclude_range[i].end = initrd_end;
+				i++;
+				if (i >= max_memory_ranges)
+					realloc_memory_ranges();
+			}
+		} /* chosen */
+
 		if (strncmp(dentry->d_name, "rtas", 4) == 0) {
 			strcat(fname, "/linux,rtas-base");
 			if ((file = fopen(fname, "r")) == NULL) {
 				perror(fname);
 				goto error_opencdir;
 			}
-			if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) {
+			if (fread(&rtas_base, sizeof(unsigned int), 1, file)
+					!= 1) {
 				perror(fname);
 				goto error_openfile;
 			}
@@ -298,7 +501,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 				perror(fname);
 				goto error_opencdir;
 			}
-			if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) {
+			if (fread(&rtas_size, sizeof(unsigned int), 1, file)
+					!= 1) {
 				perror(fname);
 				goto error_openfile;
 			}
@@ -307,6 +511,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			exclude_range[i].start = rtas_base;
 			exclude_range[i].end = rtas_base + rtas_size;
 			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(rtas_base, rtas_size);
 		} /* rtas */
 
 		if (!strncmp(dentry->d_name, "memory@", 7) ||
@@ -336,6 +542,48 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 			fclose(file);
 			closedir(cdir);
 		} /* memory */
+
+		if (strncmp(dentry->d_name, "pci@", 4) == 0) {
+			strcat(fname, "/linux,tce-base");
+			file = fopen(fname, "r");
+			if (!file) {
+				closedir(cdir);
+				if (errno == ENOENT) {
+					/* Non LPAR */
+					errno = 0;
+					continue;
+				}
+				perror(fname);
+				goto error_opendir;
+			}
+			if (fread(&tce_base, sizeof(unsigned long), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+				return -1;
+			}
+			memset(fname, 0, sizeof(fname));
+			strcpy(fname, device_tree);
+			strcat(fname, dentry->d_name);
+			strcat(fname, "/linux,tce-size");
+			file = fopen(fname, "r");
+			if (!file) {
+				perror(fname);
+				goto error_opencdir;
+			}
+			if (fread(&tce_size, sizeof(unsigned int), 1, file)
+					!= 1) {
+				perror(fname);
+				goto error_openfile;
+			}
+			/* Add tce to exclude_range - NON-LPAR only */
+			exclude_range[i].start = tce_base;
+			exclude_range[i].end = tce_base + tce_size;
+			i++;
+			if (kexec_flags & KEXEC_ON_CRASH)
+				add_usable_mem_rgns(tce_base, tce_size);
+			closedir(cdir);
+		} /* pci */
 	}
 	closedir(dir);
 
@@ -347,8 +595,8 @@ static int get_devtree_details(unsigned long UNUSED(kexec_flags))
 	int k;
 	for (k = 0; k < i; k++)
 		fprintf(stderr, "exclude_range sorted exclude_range[%d] "
-				"start:%llx, end:%llx\n", k, exclude_range[k].start,
-				exclude_range[k].end);
+			"start:%llx, end:%llx\n", k, exclude_range[k].start,
+			exclude_range[k].end);
 #endif
 	return 0;
 
@@ -532,7 +780,3 @@ void arch_update_purgatory(struct kexec_info *UNUSED(info))
 {
 }
 
-int is_crashkernel_mem_reserved(void)
-{
-	return 0; /* kdump is not supported on this platform (yet) */
-}
diff --git a/kexec/arch/ppc/kexec-ppc.h b/kexec/arch/ppc/kexec-ppc.h
index 6cec467..fc0471f 100644
--- a/kexec/arch/ppc/kexec-ppc.h
+++ b/kexec/arch/ppc/kexec-ppc.h
@@ -1,6 +1,11 @@
 #ifndef KEXEC_PPC_H
 #define KEXEC_PPC_H
 
+#define MAXBYTES	128
+#define MAX_LINE	160
+#define CORE_TYPE_ELF32	1
+#define CORE_TYPE_ELF64	2
+
 extern unsigned char setup_simple_start[];
 extern uint32_t setup_simple_size;
 
@@ -16,6 +21,8 @@ extern struct {
 	uint32_t spr8;
 } setup_dol_regs;
 
+#define SIZE_16M	(16*1024*1024UL)
+
 int elf_ppc_probe(const char *buf, off_t len);
 int elf_ppc_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
@@ -37,4 +44,29 @@ void dol_ppc_usage(void);
  */
 #define KERNEL_ACCESS_TOP (24 * 1024 * 1024)
 
+/* boot block version 17 as defined by the linux kernel */
+struct bootblock {
+	unsigned magic,
+		totalsize,
+		off_dt_struct,
+		off_dt_strings,
+		off_mem_rsvmap,
+		version,
+		last_comp_version,
+		boot_physid,
+		dt_strings_size,
+		dt_struct_size;
+};
+
+typedef struct mem_rgns {
+	unsigned int size;
+	struct memory_range *ranges;
+} mem_rgns_t;
+extern mem_rgns_t usablemem_rgns;
+extern int max_memory_ranges;
+extern unsigned long long initrd_base, initrd_size;
+extern unsigned char reuse_initrd;
+#define COMMAND_LINE_SIZE	512 /* from kernel */
+/*fs2dt*/
+void reserve(unsigned long long where, unsigned long long length);
 #endif /* KEXEC_PPC_H */
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
index 0dd18b6..72289a0 100644
--- a/purgatory/arch/ppc/Makefile
+++ b/purgatory/arch/ppc/Makefile
@@ -2,7 +2,7 @@
 # Purgatory ppc
 #
 
-ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap.S
+ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap_32.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c
diff --git a/purgatory/arch/ppc/purgatory-ppc.c b/purgatory/arch/ppc/purgatory-ppc.c
index 01d0f38..3d7d484 100644
--- a/purgatory/arch/ppc/purgatory-ppc.c
+++ b/purgatory/arch/ppc/purgatory-ppc.c
@@ -1,19 +1,41 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Created by: Mohan Kumar M (mohan@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2005. All rights reserved
+ *
+ * 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 (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
 #include <purgatory.h>
 #include "purgatory-ppc.h"
 
-unsigned int pul_stack = 0;
-unsigned int dt_offset = 0;
-unsigned int kernel = 0;
-unsigned int epapr_magic = 0;
-unsigned int mem_size = 0;
+unsigned int panic_kernel = 0;
+unsigned long backup_start = 0;
+unsigned long stack = 0;
+unsigned long dt_offset = 0;
+unsigned long my_toc = 0;
+unsigned long kernel = 0;
 
 void setup_arch(void)
 {
-	/* Nothing for now */
+	return;
 }
 
-/* This function can be used to execute after the SHA256 verification. */
 void post_verification_setup_arch(void)
 {
-	/* Nothing for now */
+	if (panic_kernel)
+		crashdump_backup_memory();
 }
diff --git a/purgatory/arch/ppc/purgatory-ppc.h b/purgatory/arch/ppc/purgatory-ppc.h
index e931cae..7eff8aa 100644
--- a/purgatory/arch/ppc/purgatory-ppc.h
+++ b/purgatory/arch/ppc/purgatory-ppc.h
@@ -1,6 +1,6 @@
 #ifndef PURGATORY_PPC_H
 #define PURGATORY_PPC_H
 
-/* nothing yet */
-
+void crashdump_backup_memory(void);
+void post_verification_setup_arch(void);
 #endif /* PURGATORY_PPC_H */
diff --git a/purgatory/arch/ppc/v2wrap.S b/purgatory/arch/ppc/v2wrap.S
deleted file mode 100644
index 79d188f..0000000
--- a/purgatory/arch/ppc/v2wrap.S
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-#  kexec: Linux boots Linux
-#
-#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
-#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
-#  Copyright (C) 2008, Sebastian Andrzej Siewior (bigeasy@linutronix.de), linutronix
-#
-#  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 (version 2 of the License).
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-#include "ppc_asm.h"
-
-# v2wrap.S
-# a wrapper to call purgatory code
-# Invokes ppc kernel with the arguments according to ePAPR v1.0
-# It assumes that the MSR is allready correct.
-
-# calling convention:
-#  no register are considred
-#
-
-#define LOADADDR(rn,name)	\
-	lis     rn,name##@h;	\
-	ori     rn,rn,name##@l;	\
-
-	.globl purgatory_start
-purgatory_start:
-
-	LOADADDR(r6,pul_stack)
-	lwz	r1,0(r6)		#setup stack
-
-	subi	r1, r1, 112
-	bl	purgatory
-	nop
-
-	LOADADDR(r6,kernel)
-	lwz	r4,0(r6)		# load the kernel address
-	mtlr	r4			# prepare branch too
-
-	LOADADDR(r6, dt_offset)
-	lwz	r3, 0(r6)		# load device-tree address
-
-	li	r4, 0
-	li	r5, 0
-
-	LOADADDR(r6, epapr_magic)	# ePAPR magic value
-	lwz	r6, 0(r6)
-
-	LOADADDR(r7, mem_size)		# the Initial Mapped Area
-	lwz	r7, 0(r6)
-
-	li	r8, 0
-	li	r9, 0
-
-	blr				# start kernel
diff --git a/purgatory/arch/ppc/v2wrap_32.S b/purgatory/arch/ppc/v2wrap_32.S
new file mode 100644
index 0000000..8442d16
--- /dev/null
+++ b/purgatory/arch/ppc/v2wrap_32.S
@@ -0,0 +1,91 @@
+#
+#  kexec: Linux boots Linux
+#
+#  Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
+#  Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
+#
+#  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 (version 2 of the License).
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# v2wrap.S
+# a wrapper to call purgatory code to backup first
+# 32kB of first kernel into the backup region
+# reserved by kexec-tools.
+# Invokes powerpc kernel with the expected arguments
+# of kernel(device-tree, phys-offset, 0)
+
+#
+# calling convention:
+#   r3 = physical number of this cpu (all cpus)
+#   r4 = address of this chunk (master only)
+# master enters at purgatory_start (aka first byte of this chunk)
+# slaves (additional cpus), if any, enter a copy of the
+# first 0x100 bytes of this code relocated to 0x0
+#
+# in other words,
+#   a copy of the first 0x100 bytes of this code is copied to 0
+#   and the slaves are sent to address 0x60
+#   with r3 = their physical cpu number.
+
+	.globl purgatory_start
+purgatory_start:	b	master
+	.org purgatory_start + 0x60     # ABI: slaves start at 60 with r3=phys
+slave:	b $
+	.org purgatory_start + 0x100    # ABI: end of copied region
+	.size purgatory_start, . - purgatory_start
+
+#
+# The above 0x100 bytes at purgatory_start are replaced with the
+# code from the kernel (or next stage) by kexec/arch/powerpc/kexec-powerpc.c
+#
+
+master:
+	or	1,1,1		# low priority to let other threads catchup
+	isync
+	mr      17,3            # save cpu id to r17
+	mr      15,4            # save physical address in reg15
+
+	lis	6,stack@h
+	ori	6,6,stack@l
+	lwz     1,0(6)          #setup stack
+
+	subi    1,1,112
+	bl      purgatory
+	nop
+
+	or	3,3,3		# ok now to high priority, lets boot
+	lis	6,0x1
+	mtctr	6		# delay a bit for slaves to catch up
+83:	bdnz	83b		# before we overwrite 0-100 again
+
+	lis	6,dt_offset@h
+	ori	6,6,dt_offset@l
+	lwz     3,0(6)          # load device-tree address
+	lwz     6,20(3)         # fetch version number
+	cmpwi   0,6,2           # v2 ?
+	blt     80f
+	stw     17,28(3)        # save my cpu number as boot_cpu_phys
+80:
+	lis	6,kernel@h
+	ori	6,6,kernel@l
+	lwz     4,0(6)          # load the kernel address
+	li	5,0		# r5 will be 0 for kernel
+	li	6,0		# clear r6 for good measure
+	mtctr	4		# prepare branch too
+
+	lwz	8,0(4)		# get the first instruction that we stole
+	stw	8,0(0)		# and put it in the slave loop at 0
+				# skip cache flush, do we care?
+
+	bctr			# start kernel

^ permalink raw reply related

* [PATCH 2/2] powerpc new toolchains fix (crt.S)
From: Maxim Uvarov @ 2010-05-11 17:47 UTC (permalink / raw)
  To: linuxppc-dev, kexec, uvarov; +Cc: lists, horms
In-Reply-To: <20100511174749.19309.44615.stgit@muvarov>


This patch is required in case if you are using new toolchains.

Best regards,
Maxim Uvarov.

From: Maxim Uvarov <muvarov@gmail.com>

Linker does not provide some vital functions when building freestanding
applications with a new toolchain, so we have to provide our own CRT.

p.s.
Without the CRT we won't see any build errors (since the purgatory is
linked with --no-undefined), but the purgatory code won't work,
'kexec -e' will just hang the board.


I added option to configure to keep code buildable for old toolchais.
But there should be way to do this automatically.

Author: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
---

 configure.ac                |    9 +++++++++
 purgatory/arch/ppc/Makefile |    3 +++
 2 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/configure.ac b/configure.ac
index fcf50e4..63606bc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,15 @@ if test "$with_xen" = yes ; then
 		AC_MSG_NOTICE([Xen support disabled])))
 fi
 
+dnl new toolchains
+if test "$ARCH" = ppc; then
+AC_ARG_WITH([oldtoolchain],
+		AC_HELP_STRING([--with-oldtoolchain],[compile without crt.S
+			required for new toolchains]),
+		AC_DEFINE(PPC_OLDTOOLCHAIN, 1,
+			[Define to compile with old toolchains]))
+fi
+
 dnl ---Sanity checks
 if test "$CC"      = "no"; then AC_MSG_ERROR([cc not found]); fi
 if test "$CPP"     = "no"; then AC_MSG_ERROR([cpp not found]); fi
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
index 72289a0..d11ec3e 100644
--- a/purgatory/arch/ppc/Makefile
+++ b/purgatory/arch/ppc/Makefile
@@ -6,6 +6,9 @@ ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap_32.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c
+ifndef PPC_OLDTOOLCHAIN
+	ppc_PURGATORY_SRCS += purgatory/arch/ppc/crt.S
+endif
 
 dist += purgatory/arch/ppc/Makefile $(ppc_PURGATORY_SRCS)		\
 	purgatory/arch/ppc/purgatory-ppc.h purgatory/arch/ppc/ppc_asm.h

^ permalink raw reply related

* [PATCH] powerpc new toolchains fix (crt.S)
From: Maxim Uvarov @ 2010-05-11 17:55 UTC (permalink / raw)
  To: linuxppc-dev, kexec; +Cc: lists, horms

Forgot to add purgatory/arch/ppc/crt.S to the patch. Resending...

--
This patch is required in case if you are using new toolchains.

Best regards,
Maxim Uvarov.

From: Maxim Uvarov <muvarov@gmail.com>

Linker does not provide some vital functions when building freestanding
applications with a new toolchain, so we have to provide our own CRT.

p.s.
Without the CRT we won't see any build errors (since the purgatory is
linked with --no-undefined), but the purgatory code won't work,
'kexec -e' will just hang the board.


I added option to configure to keep code buildable for old toolchais.
But there should be way to do this automatically.

Author: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Maxim Uvarov <muvarov@gmail.com>
---

 configure.ac                |    9 +
 purgatory/arch/ppc/Makefile |    3 
 purgatory/arch/ppc/crt.S    |  262 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+), 0 deletions(-)
 create mode 100644 purgatory/arch/ppc/crt.S

diff --git a/configure.ac b/configure.ac
index fcf50e4..63606bc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,15 @@ if test "$with_xen" = yes ; then
 		AC_MSG_NOTICE([Xen support disabled])))
 fi
 
+dnl new toolchains
+if test "$ARCH" = ppc; then
+AC_ARG_WITH([oldtoolchain],
+		AC_HELP_STRING([--with-oldtoolchain],[compile without crt.S
+			required for new toolchains]),
+		AC_DEFINE(PPC_OLDTOOLCHAIN, 1,
+			[Define to compile with old toolchains]))
+fi
+
 dnl ---Sanity checks
 if test "$CC"      = "no"; then AC_MSG_ERROR([cc not found]); fi
 if test "$CPP"     = "no"; then AC_MSG_ERROR([cpp not found]); fi
diff --git a/purgatory/arch/ppc/Makefile b/purgatory/arch/ppc/Makefile
index 72289a0..d11ec3e 100644
--- a/purgatory/arch/ppc/Makefile
+++ b/purgatory/arch/ppc/Makefile
@@ -6,6 +6,9 @@ ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap_32.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c
 ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c
+ifndef PPC_OLDTOOLCHAIN
+	ppc_PURGATORY_SRCS += purgatory/arch/ppc/crt.S
+endif
 
 dist += purgatory/arch/ppc/Makefile $(ppc_PURGATORY_SRCS)		\
 	purgatory/arch/ppc/purgatory-ppc.h purgatory/arch/ppc/ppc_asm.h
diff --git a/purgatory/arch/ppc/crt.S b/purgatory/arch/ppc/crt.S
new file mode 100644
index 0000000..d7a44bd
--- /dev/null
+++ b/purgatory/arch/ppc/crt.S
@@ -0,0 +1,262 @@
+/* This is from linux-2.6/arch/powerpc/lib/crtsavres.S:
+ *
+ * Special support for eabi and SVR4
+ *
+ *   Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
+ *   Copyright 2008 Freescale Semiconductor, Inc.
+ *   Written By Michael Meissner
+ *
+ * Based on gcc/config/rs6000/crtsavres.asm from gcc
+ *
+ * This file 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, or (at your option) any
+ * later version.
+ *
+ * In addition to the permissions in the GNU General Public License, the
+ * Free Software Foundation gives you unlimited permission to link the
+ * compiled version of this file with other programs, and to distribute
+ * those programs without any restriction coming from the use of this
+ * file.  (The General Public License restrictions do apply in other
+ * respects; for example, they cover modification of the file, and
+ * distribution when not linked into another program.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ *    As a special exception, if you link this library with files
+ *    compiled with GCC to produce an executable, this does not cause
+ *    the resulting executable to be covered by the GNU General Public License.
+ *    This exception does not however invalidate any other reasons why
+ *    the executable file might be covered by the GNU General Public License.
+ */
+
+/* On PowerPC64 Linux, these functions are provided by the linker.  */
+#ifndef __powerpc64__
+
+#define _GLOBAL(name) \
+	.type name,@function; \
+	.globl name; \
+name:
+
+/* Routines for saving integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer save area.  */
+
+_GLOBAL(_savegpr_14)
+_GLOBAL(_save32gpr_14)
+	stw	14,-72(11)	/* save gp registers */
+_GLOBAL(_savegpr_15)
+_GLOBAL(_save32gpr_15)
+	stw	15,-68(11)
+_GLOBAL(_savegpr_16)
+_GLOBAL(_save32gpr_16)
+	stw	16,-64(11)
+_GLOBAL(_savegpr_17)
+_GLOBAL(_save32gpr_17)
+	stw	17,-60(11)
+_GLOBAL(_savegpr_18)
+_GLOBAL(_save32gpr_18)
+	stw	18,-56(11)
+_GLOBAL(_savegpr_19)
+_GLOBAL(_save32gpr_19)
+	stw	19,-52(11)
+_GLOBAL(_savegpr_20)
+_GLOBAL(_save32gpr_20)
+	stw	20,-48(11)
+_GLOBAL(_savegpr_21)
+_GLOBAL(_save32gpr_21)
+	stw	21,-44(11)
+_GLOBAL(_savegpr_22)
+_GLOBAL(_save32gpr_22)
+	stw	22,-40(11)
+_GLOBAL(_savegpr_23)
+_GLOBAL(_save32gpr_23)
+	stw	23,-36(11)
+_GLOBAL(_savegpr_24)
+_GLOBAL(_save32gpr_24)
+	stw	24,-32(11)
+_GLOBAL(_savegpr_25)
+_GLOBAL(_save32gpr_25)
+	stw	25,-28(11)
+_GLOBAL(_savegpr_26)
+_GLOBAL(_save32gpr_26)
+	stw	26,-24(11)
+_GLOBAL(_savegpr_27)
+_GLOBAL(_save32gpr_27)
+	stw	27,-20(11)
+_GLOBAL(_savegpr_28)
+_GLOBAL(_save32gpr_28)
+	stw	28,-16(11)
+_GLOBAL(_savegpr_29)
+_GLOBAL(_save32gpr_29)
+	stw	29,-12(11)
+_GLOBAL(_savegpr_30)
+_GLOBAL(_save32gpr_30)
+	stw	30,-8(11)
+_GLOBAL(_savegpr_31)
+_GLOBAL(_save32gpr_31)
+	stw	31,-4(11)
+	blr
+
+/* Routines for restoring integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area.  */
+
+_GLOBAL(_restgpr_14)
+_GLOBAL(_rest32gpr_14)
+	lwz	14,-72(11)	/* restore gp registers */
+_GLOBAL(_restgpr_15)
+_GLOBAL(_rest32gpr_15)
+	lwz	15,-68(11)
+_GLOBAL(_restgpr_16)
+_GLOBAL(_rest32gpr_16)
+	lwz	16,-64(11)
+_GLOBAL(_restgpr_17)
+_GLOBAL(_rest32gpr_17)
+	lwz	17,-60(11)
+_GLOBAL(_restgpr_18)
+_GLOBAL(_rest32gpr_18)
+	lwz	18,-56(11)
+_GLOBAL(_restgpr_19)
+_GLOBAL(_rest32gpr_19)
+	lwz	19,-52(11)
+_GLOBAL(_restgpr_20)
+_GLOBAL(_rest32gpr_20)
+	lwz	20,-48(11)
+_GLOBAL(_restgpr_21)
+_GLOBAL(_rest32gpr_21)
+	lwz	21,-44(11)
+_GLOBAL(_restgpr_22)
+_GLOBAL(_rest32gpr_22)
+	lwz	22,-40(11)
+_GLOBAL(_restgpr_23)
+_GLOBAL(_rest32gpr_23)
+	lwz	23,-36(11)
+_GLOBAL(_restgpr_24)
+_GLOBAL(_rest32gpr_24)
+	lwz	24,-32(11)
+_GLOBAL(_restgpr_25)
+_GLOBAL(_rest32gpr_25)
+	lwz	25,-28(11)
+_GLOBAL(_restgpr_26)
+_GLOBAL(_rest32gpr_26)
+	lwz	26,-24(11)
+_GLOBAL(_restgpr_27)
+_GLOBAL(_rest32gpr_27)
+	lwz	27,-20(11)
+_GLOBAL(_restgpr_28)
+_GLOBAL(_rest32gpr_28)
+	lwz	28,-16(11)
+_GLOBAL(_restgpr_29)
+_GLOBAL(_rest32gpr_29)
+	lwz	29,-12(11)
+_GLOBAL(_restgpr_30)
+_GLOBAL(_rest32gpr_30)
+	lwz	30,-8(11)
+_GLOBAL(_restgpr_31)
+_GLOBAL(_rest32gpr_31)
+	lwz	31,-4(11)
+	blr
+
+/* Routines for restoring integer registers, called by the compiler.  */
+/* Called with r11 pointing to the stack header word of the caller of the */
+/* function, just beyond the end of the integer restore area.  */
+
+_GLOBAL(_restgpr_14_x)
+_GLOBAL(_rest32gpr_14_x)
+	lwz	14,-72(11)	/* restore gp registers */
+_GLOBAL(_restgpr_15_x)
+_GLOBAL(_rest32gpr_15_x)
+	lwz	15,-68(11)
+_GLOBAL(_restgpr_16_x)
+_GLOBAL(_rest32gpr_16_x)
+	lwz	16,-64(11)
+_GLOBAL(_restgpr_17_x)
+_GLOBAL(_rest32gpr_17_x)
+	lwz	17,-60(11)
+_GLOBAL(_restgpr_18_x)
+_GLOBAL(_rest32gpr_18_x)
+	lwz	18,-56(11)
+_GLOBAL(_restgpr_19_x)
+_GLOBAL(_rest32gpr_19_x)
+	lwz	19,-52(11)
+_GLOBAL(_restgpr_20_x)
+_GLOBAL(_rest32gpr_20_x)
+	lwz	20,-48(11)
+_GLOBAL(_restgpr_21_x)
+_GLOBAL(_rest32gpr_21_x)
+	lwz	21,-44(11)
+_GLOBAL(_restgpr_22_x)
+_GLOBAL(_rest32gpr_22_x)
+	lwz	22,-40(11)
+_GLOBAL(_restgpr_23_x)
+_GLOBAL(_rest32gpr_23_x)
+	lwz	23,-36(11)
+_GLOBAL(_restgpr_24_x)
+_GLOBAL(_rest32gpr_24_x)
+	lwz	24,-32(11)
+_GLOBAL(_restgpr_25_x)
+_GLOBAL(_rest32gpr_25_x)
+	lwz	25,-28(11)
+_GLOBAL(_restgpr_26_x)
+_GLOBAL(_rest32gpr_26_x)
+	lwz	26,-24(11)
+_GLOBAL(_restgpr_27_x)
+_GLOBAL(_rest32gpr_27_x)
+	lwz	27,-20(11)
+_GLOBAL(_restgpr_28_x)
+_GLOBAL(_rest32gpr_28_x)
+	lwz	28,-16(11)
+_GLOBAL(_restgpr_29_x)
+_GLOBAL(_rest32gpr_29_x)
+	lwz	29,-12(11)
+_GLOBAL(_restgpr_30_x)
+_GLOBAL(_rest32gpr_30_x)
+	lwz	30,-8(11)
+_GLOBAL(_restgpr_31_x)
+_GLOBAL(_rest32gpr_31_x)
+	lwz	0,4(11)
+	lwz	31,-4(11)
+	mtlr	0
+	mr	1,11
+	blr
+
+/* This is from linux-2.6/arch/powerpc/kernel/misc_32.S
+ * 
+ * This file contains miscellaneous low-level functions.
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * 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.
+ *
+ */
+
+_GLOBAL(__lshrdi3)
+	subfic	6,5,32
+	srw	4,4,5	# LSW = count > 31 ? 0 : LSW >> count
+	addi	7,5,32	# could be xori, or addi with -32
+	slw	6,3,6	# t1 = count > 31 ? 0 : MSW << (32-count)
+	srw	7,3,7	# t2 = count < 32 ? 0 : MSW >> (count-32)
+	or	4,4,6	# LSW |= t1
+	srw	3,3,5	# MSW = MSW >> count
+	or	4,4,7	# LSW |= t2
+	blr
+
+#endif

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox