arch/powerpc/kernel/crash_dump.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/crash_dump.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/crash_dump.c
Extension
.c
Size
3446 bytes
Lines
135
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Routines for doing kexec-based kdump.
 *
 * Copyright (C) 2005, IBM Corp.
 *
 * Created by: Michael Ellerman
 */

#undef DEBUG

#include <linux/crash_dump.h>
#include <linux/io.h>
#include <linux/memblock.h>
#include <linux/of.h>
#include <asm/text-patching.h>
#include <asm/kdump.h>
#include <asm/firmware.h>
#include <linux/uio.h>
#include <asm/rtas.h>
#include <asm/inst.h>
#include <asm/fadump.h>

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

#ifndef CONFIG_NONSTATIC_KERNEL
void __init reserve_kdump_trampoline(void)
{
	memblock_reserve(0, KDUMP_RESERVE_LIMIT);
}

static void __init create_trampoline(unsigned long addr)
{
	u32 *p = (u32 *)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.
	 */
	patch_instruction(p, ppc_inst(PPC_RAW_NOP()));
	patch_branch(p + 1, addr + PHYSICAL_START, 0);
}

void __init setup_kdump_trampoline(void)
{
	unsigned long i;

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

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

#ifdef CONFIG_PPC_PSERIES
	create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
	create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
#endif /* CONFIG_PPC_PSERIES */

	DBG(" <- setup_kdump_trampoline()\n");
}
#endif /* CONFIG_NONSTATIC_KERNEL */

ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn,
			size_t csize, unsigned long offset)
{
	void  *vaddr;
	phys_addr_t paddr;

	if (!csize)
		return 0;

	csize = min_t(size_t, csize, PAGE_SIZE);
	paddr = pfn << PAGE_SHIFT;

	if (memblock_is_region_memory(paddr, csize)) {
		vaddr = __va(paddr);
		csize = copy_to_iter(vaddr + offset, csize, iter);
	} else {
		vaddr = ioremap_cache(paddr, PAGE_SIZE);
		csize = copy_to_iter(vaddr + offset, csize, iter);
		iounmap(vaddr);

Annotation

Implementation Notes