Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0cc4746c authored by Michael Ellerman's avatar Michael Ellerman Committed by Paul Mackerras
Browse files

[PATCH] powerpc: Reroute interrupts from 0 + offset to PHYSICAL_START + offset



Regardless of where the kernel's linked we always get interrupts at low
addresses. This patch creates a trampoline in the first 3 pages of memory,
where interrupts land, and patches those addresses to jump into the real
kernel code at PHYSICAL_START.

We also need to reserve the trampoline code and a bit more in prom.c

Signed-off-by: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 8c4f1f29
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_IBMEBUS)           += ibmebus.o
obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o

ifeq ($(CONFIG_PPC_MERGE),y)

+53 −0
Original line number Diff line number Diff line
/*
 * Routines for doing kexec-based kdump.
 *
 * Copyright (C) 2005, IBM Corp.
 *
 * Created by: Michael Ellerman
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#undef DEBUG

#include <asm/kdump.h>
#include <asm/lmb.h>
#include <asm/firmware.h>

#ifdef DEBUG
#include <asm/udbg.h>
#define DBG(fmt...) udbg_printf(fmt)
#else
#define DBG(fmt...)
#endif

static void __init create_trampoline(unsigned long addr)
{
	/* The maximum range of a single instruction branch, is the current
	 * instruction's address + (32 MB - 4) bytes. For the trampoline we
	 * need to branch to current address + 32 MB. So we insert a nop at
	 * the trampoline address, then the next instruction (+ 4 bytes)
	 * does a branch to (32 MB - 4). The net effect is that when we
	 * branch to "addr" we jump to ("addr" + 32 MB). Although it requires
	 * two instructions it doesn't require any registers.
	 */
	create_instruction(addr, 0x60000000); /* nop */
	create_branch(addr + 4, addr + PHYSICAL_START, 0);
}

void __init kdump_setup(void)
{
	unsigned long i;

	DBG(" -> kdump_setup()\n");

	for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
		create_trampoline(i);
	}

	create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
	create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);

	DBG(" <- kdump_setup()\n");
}
+5 −1
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/kdump.h>
#include <asm/smp.h>
#include <asm/system.h>
#include <asm/mmu.h>
@@ -1335,11 +1336,14 @@ void __init early_init_devtree(void *params)
	of_scan_flat_dt(early_init_dt_scan_memory, NULL);
	lmb_enforce_memory_limit(memory_limit);
	lmb_analyze();
	lmb_reserve(0, __pa(klimit));

	DBG("Phys. mem: %lx\n", lmb_phys_mem_size());

	/* Reserve LMB regions used by kernel, initrd, dt, etc... */
	lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
#ifdef CONFIG_CRASH_DUMP
	lmb_reserve(0, KDUMP_RESERVE_LIMIT);
#endif
	early_reserve_mem();

	DBG("Scanning CPUs ...\n");
+5 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/kdump.h>
#include <asm/prom.h>
#include <asm/processor.h>
#include <asm/pgtable.h>
@@ -268,6 +269,10 @@ void __init early_setup(unsigned long dt_ptr)
	}
	ppc_md = **mach;

#ifdef CONFIG_CRASH_DUMP
	kdump_setup();
#endif

	DBG("Found, Initializing memory management...\n");

	/*
+13 −0
Original line number Diff line number Diff line
#ifndef _PPC64_KDUMP_H
#define _PPC64_KDUMP_H

/* How many bytes to reserve at zero for kdump. The reserve limit should
 * be greater or equal to the trampoline's end address. */
#define KDUMP_RESERVE_LIMIT	0x8000

#define KDUMP_TRAMPOLINE_START	0x0100
#define KDUMP_TRAMPOLINE_END	0x3000

extern void kdump_setup(void);

#endif /* __PPC64_KDUMP_H */