1
2
3
4
5
6
7
8
9
10
11
12#undef DEBUG
13
14#include <linux/crash_dump.h>
15#include <linux/bootmem.h>
16#include <linux/io.h>
17#include <linux/memblock.h>
18#include <asm/code-patching.h>
19#include <asm/kdump.h>
20#include <asm/prom.h>
21#include <asm/firmware.h>
22#include <asm/uaccess.h>
23#include <asm/rtas.h>
24
25#ifdef DEBUG
26#include <asm/udbg.h>
27#define DBG(fmt...) udbg_printf(fmt)
28#else
29#define DBG(fmt...)
30#endif
31
32#ifndef CONFIG_NONSTATIC_KERNEL
33void __init reserve_kdump_trampoline(void)
34{
35 memblock_reserve(0, KDUMP_RESERVE_LIMIT);
36}
37
38static void __init create_trampoline(unsigned long addr)
39{
40 unsigned int *p = (unsigned int *)addr;
41
42
43
44
45
46
47
48
49
50 patch_instruction(p, PPC_INST_NOP);
51 patch_branch(++p, addr + PHYSICAL_START, 0);
52}
53
54void __init setup_kdump_trampoline(void)
55{
56 unsigned long i;
57
58 DBG(" -> setup_kdump_trampoline()\n");
59
60 for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) {
61 create_trampoline(i);
62 }
63
64#ifdef CONFIG_PPC_PSERIES
65 create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START);
66 create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START);
67#endif
68
69 DBG(" <- setup_kdump_trampoline()\n");
70}
71#endif
72
73static size_t copy_oldmem_vaddr(void *vaddr, char *buf, size_t csize,
74 unsigned long offset, int userbuf)
75{
76 if (userbuf) {
77 if (copy_to_user((char __user *)buf, (vaddr + offset), csize))
78 return -EFAULT;
79 } else
80 memcpy(buf, (vaddr + offset), csize);
81
82 return csize;
83}
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
99 size_t csize, unsigned long offset, int userbuf)
100{
101 void *vaddr;
102 phys_addr_t paddr;
103
104 if (!csize)
105 return 0;
106
107 csize = min_t(size_t, csize, PAGE_SIZE);
108 paddr = pfn << PAGE_SHIFT;
109
110 if (memblock_is_region_memory(paddr, csize)) {
111 vaddr = __va(paddr);
112 csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
113 } else {
114 vaddr = __ioremap(paddr, PAGE_SIZE, 0);
115 csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
116 iounmap(vaddr);
117 }
118
119 return csize;
120}
121
122#ifdef CONFIG_PPC_RTAS
123
124
125
126
127void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
128{
129 unsigned long addr;
130 const __be32 *basep, *sizep;
131 unsigned int rtas_start = 0, rtas_end = 0;
132
133 basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
134 sizep = of_get_property(rtas.dev, "rtas-size", NULL);
135
136 if (basep && sizep) {
137 rtas_start = be32_to_cpup(basep);
138 rtas_end = rtas_start + be32_to_cpup(sizep);
139 }
140
141 for (addr = begin; addr < end; addr += PAGE_SIZE) {
142
143 if (addr <= rtas_end && ((addr + PAGE_SIZE) > rtas_start))
144 continue;
145
146 free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
147 }
148}
149#endif
150