1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Routines for doing kexec-based kdump. |
4 | * |
5 | * Copyright (C) 2005, IBM Corp. |
6 | * |
7 | * Created by: Michael Ellerman |
8 | */ |
9 | |
10 | #undef DEBUG |
11 | |
12 | #include <linux/crash_dump.h> |
13 | #include <linux/io.h> |
14 | #include <linux/memblock.h> |
15 | #include <linux/of.h> |
16 | #include <asm/code-patching.h> |
17 | #include <asm/kdump.h> |
18 | #include <asm/firmware.h> |
19 | #include <linux/uio.h> |
20 | #include <asm/rtas.h> |
21 | #include <asm/inst.h> |
22 | #include <asm/fadump.h> |
23 | |
24 | #ifdef DEBUG |
25 | #include <asm/udbg.h> |
26 | #define DBG(fmt...) udbg_printf(fmt) |
27 | #else |
28 | #define DBG(fmt...) |
29 | #endif |
30 | |
31 | #ifndef CONFIG_NONSTATIC_KERNEL |
32 | void __init reserve_kdump_trampoline(void) |
33 | { |
34 | memblock_reserve(base: 0, size: KDUMP_RESERVE_LIMIT); |
35 | } |
36 | |
37 | static void __init create_trampoline(unsigned long addr) |
38 | { |
39 | u32 *p = (u32 *)addr; |
40 | |
41 | /* The maximum range of a single instruction branch, is the current |
42 | * instruction's address + (32 MB - 4) bytes. For the trampoline we |
43 | * need to branch to current address + 32 MB. So we insert a nop at |
44 | * the trampoline address, then the next instruction (+ 4 bytes) |
45 | * does a branch to (32 MB - 4). The net effect is that when we |
46 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires |
47 | * two instructions it doesn't require any registers. |
48 | */ |
49 | patch_instruction(p, ppc_inst(PPC_RAW_NOP())); |
50 | patch_branch(p + 1, addr + PHYSICAL_START, 0); |
51 | } |
52 | |
53 | void __init setup_kdump_trampoline(void) |
54 | { |
55 | unsigned long i; |
56 | |
57 | DBG(" -> setup_kdump_trampoline()\n" ); |
58 | |
59 | for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { |
60 | create_trampoline(addr: i); |
61 | } |
62 | |
63 | #ifdef CONFIG_PPC_PSERIES |
64 | create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); |
65 | create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); |
66 | #endif /* CONFIG_PPC_PSERIES */ |
67 | |
68 | DBG(" <- setup_kdump_trampoline()\n" ); |
69 | } |
70 | #endif /* CONFIG_NONSTATIC_KERNEL */ |
71 | |
72 | ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn, |
73 | size_t csize, unsigned long offset) |
74 | { |
75 | void *vaddr; |
76 | phys_addr_t paddr; |
77 | |
78 | if (!csize) |
79 | return 0; |
80 | |
81 | csize = min_t(size_t, csize, PAGE_SIZE); |
82 | paddr = pfn << PAGE_SHIFT; |
83 | |
84 | if (memblock_is_region_memory(base: paddr, size: csize)) { |
85 | vaddr = __va(paddr); |
86 | csize = copy_to_iter(addr: vaddr + offset, bytes: csize, i: iter); |
87 | } else { |
88 | vaddr = ioremap_cache(offset: paddr, PAGE_SIZE); |
89 | csize = copy_to_iter(addr: vaddr + offset, bytes: csize, i: iter); |
90 | iounmap(addr: vaddr); |
91 | } |
92 | |
93 | return csize; |
94 | } |
95 | |
96 | /* |
97 | * Return true only when kexec based kernel dump capturing method is used. |
98 | * This ensures all restritions applied for kdump case are not automatically |
99 | * applied for fadump case. |
100 | */ |
101 | bool is_kdump_kernel(void) |
102 | { |
103 | return !is_fadump_active() && elfcorehdr_addr != ELFCORE_ADDR_MAX; |
104 | } |
105 | EXPORT_SYMBOL_GPL(is_kdump_kernel); |
106 | |
107 | #ifdef CONFIG_PPC_RTAS |
108 | /* |
109 | * The crashkernel region will almost always overlap the RTAS region, so |
110 | * we have to be careful when shrinking the crashkernel region. |
111 | */ |
112 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end) |
113 | { |
114 | unsigned long addr; |
115 | const __be32 *basep, *sizep; |
116 | unsigned int rtas_start = 0, rtas_end = 0; |
117 | |
118 | basep = of_get_property(rtas.dev, "linux,rtas-base" , NULL); |
119 | sizep = of_get_property(rtas.dev, "rtas-size" , NULL); |
120 | |
121 | if (basep && sizep) { |
122 | rtas_start = be32_to_cpup(basep); |
123 | rtas_end = rtas_start + be32_to_cpup(sizep); |
124 | } |
125 | |
126 | for (addr = begin; addr < end; addr += PAGE_SIZE) { |
127 | /* Does this page overlap with the RTAS region? */ |
128 | if (addr <= rtas_end && ((addr + PAGE_SIZE) > rtas_start)) |
129 | continue; |
130 | |
131 | free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT)); |
132 | } |
133 | } |
134 | #endif |
135 | |