aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/machine_kexec.c
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-05-28 23:09:12 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-06-04 17:11:18 -0400
commit867e359b97c970a60626d5d76bbe2a8fadbf38fb (patch)
treec5ccbb7f5172e8555977119608ecb1eee3cc37e3 /arch/tile/kernel/machine_kexec.c
parent5360bd776f73d0a7da571d72a09a03f237e99900 (diff)
arch/tile: core support for Tilera 32-bit chips.
This change is the core kernel support for TILEPro and TILE64 chips. No driver support (except the console driver) is included yet. This includes the relevant Linux headers in asm/; the low-level low-level "Tile architecture" headers in arch/, which are shared with the hypervisor, etc., and are build-system agnostic; and the relevant hypervisor headers in hv/. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Reviewed-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/tile/kernel/machine_kexec.c')
-rw-r--r--arch/tile/kernel/machine_kexec.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
new file mode 100644
index 00000000000..ed3e1cb8dcc
--- /dev/null
+++ b/arch/tile/kernel/machine_kexec.c
@@ -0,0 +1,291 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * based on machine_kexec.c from other architectures in linux-2.6.18
15 */
16
17#include <linux/mm.h>
18#include <linux/kexec.h>
19#include <linux/delay.h>
20#include <linux/reboot.h>
21#include <linux/errno.h>
22#include <linux/vmalloc.h>
23#include <linux/cpumask.h>
24#include <linux/kernel.h>
25#include <linux/elf.h>
26#include <linux/highmem.h>
27#include <linux/mmu_context.h>
28#include <linux/io.h>
29#include <linux/timex.h>
30#include <asm/pgtable.h>
31#include <asm/pgalloc.h>
32#include <asm/cacheflush.h>
33#include <asm/checksum.h>
34#include <hv/hypervisor.h>
35
36
37/*
38 * This stuff is not in elf.h and is not in any other kernel include.
39 * This stuff is needed below in the little boot notes parser to
40 * extract the command line so we can pass it to the hypervisor.
41 */
42struct Elf32_Bhdr {
43 Elf32_Word b_signature;
44 Elf32_Word b_size;
45 Elf32_Half b_checksum;
46 Elf32_Half b_records;
47};
48#define ELF_BOOT_MAGIC 0x0E1FB007
49#define EBN_COMMAND_LINE 0x00000004
50#define roundupsz(X) (((X) + 3) & ~3)
51
52/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
53
54
55void machine_shutdown(void)
56{
57 /*
58 * Normally we would stop all the other processors here, but
59 * the check in machine_kexec_prepare below ensures we'll only
60 * get this far if we've been booted with "nosmp" on the
61 * command line or without CONFIG_SMP so there's nothing to do
62 * here (for now).
63 */
64}
65
66void machine_crash_shutdown(struct pt_regs *regs)
67{
68 /*
69 * Cannot happen. This type of kexec is disabled on this
70 * architecture (and enforced in machine_kexec_prepare below).
71 */
72}
73
74
75int machine_kexec_prepare(struct kimage *image)
76{
77 if (num_online_cpus() > 1) {
78 printk(KERN_WARNING "%s: detected attempt to kexec "
79 "with num_online_cpus() > 1\n",
80 __func__);
81 return -ENOSYS;
82 }
83 if (image->type != KEXEC_TYPE_DEFAULT) {
84 printk(KERN_WARNING "%s: detected attempt to kexec "
85 "with unsupported type: %d\n",
86 __func__,
87 image->type);
88 return -ENOSYS;
89 }
90 return 0;
91}
92
93void machine_kexec_cleanup(struct kimage *image)
94{
95 /*
96 * We did nothing in machine_kexec_prepare,
97 * so we have nothing to do here.
98 */
99}
100
101/*
102 * If we can find elf boot notes on this page, return the command
103 * line. Otherwise, silently return null. Somewhat kludgy, but no
104 * good way to do this without significantly rearchitecting the
105 * architecture-independent kexec code.
106 */
107
108static unsigned char *kexec_bn2cl(void *pg)
109{
110 struct Elf32_Bhdr *bhdrp;
111 Elf32_Nhdr *nhdrp;
112 unsigned char *desc;
113 unsigned char *command_line;
114 __sum16 csum;
115
116 bhdrp = (struct Elf32_Bhdr *) pg;
117
118 /*
119 * This routine is invoked for every source page, so make
120 * sure to quietly ignore every impossible page.
121 */
122 if (bhdrp->b_signature != ELF_BOOT_MAGIC ||
123 bhdrp->b_size > PAGE_SIZE)
124 return 0;
125
126 /*
127 * If we get a checksum mismatch, it's possible that this is
128 * just a false positive, but relatively unlikely. We dump
129 * out the contents of the section so we can diagnose better.
130 */
131 csum = ip_compute_csum(pg, bhdrp->b_size);
132 if (csum != 0) {
133 int i;
134 unsigned char *p = pg;
135 int nbytes = min((Elf32_Word)1000, bhdrp->b_size);
136 printk(KERN_INFO "%s: bad checksum %#x\n", __func__, csum);
137 printk(KERN_INFO "bytes (%d):", bhdrp->b_size);
138 for (i = 0; i < nbytes; ++i)
139 printk(" %02x", p[i]);
140 if (bhdrp->b_size != nbytes)
141 printk(" ...");
142 printk("\n");
143 return 0;
144 }
145
146 nhdrp = (Elf32_Nhdr *) (bhdrp + 1);
147
148 while (nhdrp->n_type != EBN_COMMAND_LINE) {
149
150 desc = (unsigned char *) (nhdrp + 1);
151 desc += roundupsz(nhdrp->n_descsz);
152
153 nhdrp = (Elf32_Nhdr *) desc;
154
155 /* still in bounds? */
156 if ((unsigned char *) (nhdrp + 1) >
157 ((unsigned char *) pg) + bhdrp->b_size) {
158
159 printk(KERN_INFO "%s: out of bounds\n", __func__);
160 return 0;
161 }
162 }
163
164 command_line = (unsigned char *) (nhdrp + 1);
165 desc = command_line;
166
167 while (*desc != '\0') {
168 desc++;
169 if (((unsigned long)desc & PAGE_MASK) != (unsigned long)pg) {
170 printk(KERN_INFO "%s: ran off end of page\n",
171 __func__);
172 return 0;
173 }
174 }
175
176 return command_line;
177}
178
179static void kexec_find_and_set_command_line(struct kimage *image)
180{
181 kimage_entry_t *ptr, entry;
182
183 unsigned char *command_line = 0;
184 unsigned char *r;
185 HV_Errno hverr;
186
187 for (ptr = &image->head;
188 (entry = *ptr) && !(entry & IND_DONE);
189 ptr = (entry & IND_INDIRECTION) ?
190 phys_to_virt((entry & PAGE_MASK)) : ptr + 1) {
191
192 if ((entry & IND_SOURCE)) {
193 void *va =
194 kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
195 r = kexec_bn2cl(va);
196 if (r) {
197 command_line = r;
198 break;
199 }
200 kunmap_atomic(va, KM_USER0);
201 }
202 }
203
204 if (command_line != 0) {
205 printk(KERN_INFO "setting new command line to \"%s\"\n",
206 command_line);
207
208 hverr = hv_set_command_line(
209 (HV_VirtAddr) command_line, strlen(command_line));
210 kunmap_atomic(command_line, KM_USER0);
211 } else {
212 printk(KERN_INFO "%s: no command line found; making empty\n",
213 __func__);
214 hverr = hv_set_command_line((HV_VirtAddr) command_line, 0);
215 }
216 if (hverr) {
217 printk(KERN_WARNING
218 "%s: call to hv_set_command_line returned error: %d\n",
219 __func__, hverr);
220
221 }
222}
223
224/*
225 * The kexec code range-checks all its PAs, so to avoid having it run
226 * amok and allocate memory and then sequester it from every other
227 * controller, we force it to come from controller zero. We also
228 * disable the oom-killer since if we do end up running out of memory,
229 * that almost certainly won't help.
230 */
231struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order)
232{
233 gfp_mask |= __GFP_THISNODE | __GFP_NORETRY;
234 return alloc_pages_node(0, gfp_mask, order);
235}
236
237static void setup_quasi_va_is_pa(void)
238{
239 HV_PTE *pgtable;
240 HV_PTE pte;
241 int i;
242
243 /*
244 * Flush our TLB to prevent conflicts between the previous contents
245 * and the new stuff we're about to add.
246 */
247 local_flush_tlb_all();
248
249 /* setup VA is PA, at least up to PAGE_OFFSET */
250
251 pgtable = (HV_PTE *)current->mm->pgd;
252 pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE);
253 pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
254
255 for (i = 0; i < pgd_index(PAGE_OFFSET); i++)
256 pgtable[i] = pfn_pte(i << (HPAGE_SHIFT - PAGE_SHIFT), pte);
257}
258
259
260NORET_TYPE void machine_kexec(struct kimage *image)
261{
262 void *reboot_code_buffer;
263 NORET_TYPE void (*rnk)(unsigned long, void *, unsigned long)
264 ATTRIB_NORET;
265
266 /* Mask all interrupts before starting to reboot. */
267 interrupt_mask_set_mask(~0ULL);
268
269 kexec_find_and_set_command_line(image);
270
271 /*
272 * Adjust the home caching of the control page to be cached on
273 * this cpu, and copy the assembly helper into the control
274 * code page, which we map in the vmalloc area.
275 */
276 homecache_change_page_home(image->control_code_page, 0,
277 smp_processor_id());
278 reboot_code_buffer = vmap(&image->control_code_page, 1, 0,
279 __pgprot(_PAGE_KERNEL | _PAGE_EXECUTABLE));
280 memcpy(reboot_code_buffer, relocate_new_kernel,
281 relocate_new_kernel_size);
282 __flush_icache_range(
283 (unsigned long) reboot_code_buffer,
284 (unsigned long) reboot_code_buffer + relocate_new_kernel_size);
285
286 setup_quasi_va_is_pa();
287
288 /* now call it */
289 rnk = reboot_code_buffer;
290 (*rnk)(image->head, reboot_code_buffer, image->start);
291}