1 Index: kexec-tools-2.0.1/kexec/arch/mips/Makefile
2 ===================================================================
3 --- kexec-tools-2.0.1.orig/kexec/arch/mips/Makefile 2008-07-15 02:46:43.000000000 +0200
4 +++ kexec-tools-2.0.1/kexec/arch/mips/Makefile 2009-09-27 19:07:26.000000000 +0200
6 mips_KEXEC_SRCS = kexec/arch/mips/kexec-mips.c
7 mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-mips.c
8 mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-rel-mips.c
9 -mips_KEXEC_SRCS += kexec/arch/mips/mips-setup-simple.S
10 +mips_KEXEC_SRCS += kexec/arch/mips/crashdump-mips.c
14 Index: kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.c
15 ===================================================================
16 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
17 +++ kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.c 2009-09-27 19:07:26.000000000 +0200
20 + * kexec: Linux boots Linux
22 + * 2005 (C) IBM Corporation.
23 + * 2008 (C) MontaVista Software, Inc.
25 + * This program is free software; you can redistribute it and/or modify
26 + * it under the terms of the GNU General Public License as published by
27 + * the Free Software Foundation (version 2 of the License).
29 + * This program is distributed in the hope that it will be useful,
30 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 + * GNU General Public License for more details.
34 + * You should have received a copy of the GNU General Public License
35 + * along with this program; if not, write to the Free Software
36 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43 +#include <sys/types.h>
44 +#include <sys/stat.h>
46 +#include "../../kexec.h"
47 +#include "../../kexec-elf.h"
48 +#include "../../kexec-syscall.h"
49 +#include "../../crashdump.h"
50 +#include "kexec-mips.h"
51 +#include "crashdump-mips.h"
53 +extern struct arch_options_t arch_options;
55 +/* Stores a sorted list of RAM memory ranges for which to create elf headers.
56 + * A separate program header is created for backup region */
57 +static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
59 +/* Memory region reserved for storing panic kernel and other data. */
60 +static struct memory_range crash_reserved_mem;
63 + * To store the memory size of the first kernel and this value will be
64 + * passed to the second kernel as command line (savemaxmem=xM).
65 + * The second kernel will be calculated saved_max_pfn based on this
68 +unsigned long long saved_max_mem = 0;
70 +/* Removes crash reserve region from list of memory chunks for whom elf program
71 + * headers have to be created. Assuming crash reserve region to be a single
72 + * continuous area fully contained inside one of the memory chunks */
73 +static int exclude_crash_reserve_region(int *nr_ranges)
75 + int i, j, tidx = -1;
76 + unsigned long long cstart, cend;
77 + struct memory_range temp_region;
79 + /* Crash reserved region. */
80 + cstart = crash_reserved_mem.start;
81 + cend = crash_reserved_mem.end;
83 + for (i = 0; i < (*nr_ranges); i++) {
84 + unsigned long long mstart, mend;
85 + mstart = crash_memory_range[i].start;
86 + mend = crash_memory_range[i].end;
87 + if (cstart < mend && cend > mstart) {
88 + if (cstart != mstart && cend != mend) {
89 + /* Split memory region */
90 + crash_memory_range[i].end = cstart - 1;
91 + temp_region.start = cend + 1;
92 + temp_region.end = mend;
93 + temp_region.type = RANGE_RAM;
95 + } else if (cstart != mstart)
96 + crash_memory_range[i].end = cstart - 1;
98 + crash_memory_range[i].start = cend + 1;
101 + /* Insert split memory region, if any. */
103 + if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
104 + /* No space to insert another element. */
105 + fprintf(stderr, "Error: Number of crash memory ranges"
106 + " excedeed the max limit\n");
109 + for (j = (*nr_ranges - 1); j >= tidx; j--)
110 + crash_memory_range[j+1] = crash_memory_range[j];
111 + crash_memory_range[tidx].start = temp_region.start;
112 + crash_memory_range[tidx].end = temp_region.end;
113 + crash_memory_range[tidx].type = temp_region.type;
118 +/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
119 + * create Elf headers. Keeping it separate from get_memory_ranges() as
120 + * requirements are different in the case of normal kexec and crashdumps.
122 + * Normal kexec needs to look at all of available physical memory irrespective
123 + * of the fact how much of it is being used by currently running kernel.
124 + * Crashdumps need to have access to memory regions actually being used by
125 + * running kernel. Expecting a different file/data structure than /proc/iomem
126 + * to look into down the line. May be something like /proc/kernelmem or may
127 + * be zone data structures exported from kernel.
129 +static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
131 + const char iomem[]= "/proc/iomem";
132 + int i, memory_ranges = 0;
133 + char line[MAX_LINE];
135 + unsigned long long start, end;
137 + fp = fopen(iomem, "r");
139 + fprintf(stderr, "Cannot open %s: %s\n",
140 + iomem, strerror(errno));
144 + /* Separate segment for backup region */
145 + crash_memory_range[0].start = BACKUP_SRC_START;
146 + crash_memory_range[0].end = BACKUP_SRC_END;
147 + crash_memory_range[0].type = RANGE_RAM;
150 + while(fgets(line, sizeof(line), fp) != 0) {
152 + int type, consumed, count;
153 + if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
155 + count = sscanf(line, "%Lx-%Lx : %n",
156 + &start, &end, &consumed);
159 + str = line + consumed;
161 + /* Only Dumping memory of type System RAM. */
162 + if (memcmp(str, "System RAM\n", 11) == 0) {
164 + } else if (memcmp(str, "Crash kernel\n", 13) == 0) {
165 + /* Reserved memory region. New kernel can
166 + * use this region to boot into. */
167 + crash_reserved_mem.start = start;
168 + crash_reserved_mem.end = end;
169 + crash_reserved_mem.type = RANGE_RAM;
175 + if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1))
176 + start = BACKUP_SRC_END + 1;
178 + crash_memory_range[memory_ranges].start = start;
179 + crash_memory_range[memory_ranges].end = end;
180 + crash_memory_range[memory_ranges].type = type;
183 + /* Segregate linearly mapped region. */
184 + if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
185 + crash_memory_range[memory_ranges-1].end = MAXMEM -1;
187 + /* Add segregated region. */
188 + crash_memory_range[memory_ranges].start = MAXMEM;
189 + crash_memory_range[memory_ranges].end = end;
190 + crash_memory_range[memory_ranges].type = type;
196 + if (exclude_crash_reserve_region(&memory_ranges) < 0)
199 + for (i = 0; i < memory_ranges; i++)
200 + if (saved_max_mem < crash_memory_range[i].end)
201 + saved_max_mem = crash_memory_range[i].end + 1;
203 + *range = crash_memory_range;
204 + *ranges = memory_ranges;
208 +/* Converts unsigned long to ascii string. */
209 +static void ultoa(unsigned long i, char *str)
215 + str[j++] = i % 10 + '0';
216 + } while ((i /=10) > 0);
219 + /* Reverse the string. */
220 + for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
227 +/* Adds the appropriate mem= options to command line, indicating the
228 + * memory region the new kernel can use to boot into. */
229 +static int cmdline_add_mem(char *cmdline, unsigned long addr, unsigned long size)
232 + char str[50], *ptr;
237 + strcpy (str, " mem=");
238 + ptr += strlen(str);
240 + strcat (str, "K@");
241 + ptr = str + strlen(str);
245 + cmdlen = strlen(cmdline) + len;
246 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
247 + die("Command line overflow\n");
248 + strcat(cmdline, str);
253 +/* Adds the elfcorehdr= command line parameter to command line. */
254 +static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
256 + int cmdlen, len, align = 1024;
257 + char str[30], *ptr;
259 + /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
260 + * Ensure 1K alignment*/
265 + strcpy(str, " elfcorehdr=");
266 + ptr += strlen(str);
270 + cmdlen = strlen(cmdline) + len;
271 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
272 + die("Command line overflow\n");
273 + strcat(cmdline, str);
277 +/* Adds the elfcorehdr= command line parameter to command line. */
278 +static int cmdline_add_savemaxmem(char *cmdline, unsigned long addr)
280 + int cmdlen, len, align = 1024;
281 + char str[30], *ptr;
283 + /* Passing in savemaxmem=xxxM format. Saves space required in cmdline.*/
284 + addr = addr/(align*align);
286 + strcpy(str, " savemaxmem=");
287 + ptr += strlen(str);
291 + cmdlen = strlen(cmdline) + len;
292 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
293 + die("Command line overflow\n");
294 + strcat(cmdline, str);
299 +static struct crash_elf_info elf_info64 =
304 + backup_src_start: BACKUP_SRC_START,
305 + backup_src_end: BACKUP_SRC_END,
306 + page_offset: PAGE_OFFSET,
307 + lowmem_limit: MAXMEM,
310 +static struct crash_elf_info elf_info32 =
315 + backup_src_start: BACKUP_SRC_START,
316 + backup_src_end: BACKUP_SRC_END,
317 + page_offset: PAGE_OFFSET,
318 + lowmem_limit: MAXMEM,
321 +/* Loads additional segments in case of a panic kernel is being loaded.
322 + * One segment for backup region, another segment for storing elf headers
323 + * for crash memory image.
325 +int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
326 + unsigned long max_addr, unsigned long min_base)
329 + unsigned long sz, elfcorehdr;
330 + int nr_ranges, align = 1024;
331 + struct memory_range *mem_range;
333 + if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
336 + /* Create a backup region segment to store backup data*/
337 + sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
339 + memset(tmp, 0, sz);
340 + info->backup_start = add_buffer(info, tmp, sz, sz, align,
341 + crash_reserved_mem.start,
342 + crash_reserved_mem.end,-1);
345 + /* Create elf header segment and store crash image data. */
346 + if (arch_options.core_header_type == CORE_TYPE_ELF64) {
347 + if (crash_create_elf64_headers(info, &elf_info64,
348 + crash_memory_range, nr_ranges,
350 + ELF_CORE_HEADER_ALIGN) < 0)
354 + if (crash_create_elf32_headers(info, &elf_info32,
355 + crash_memory_range, nr_ranges,
357 + ELF_CORE_HEADER_ALIGN) < 0)
361 + if (crash_create_elf32_headers(info, &elf_info32,
362 + crash_memory_range, nr_ranges,
364 + ELF_CORE_HEADER_ALIGN) < 0)
367 + elfcorehdr = add_buffer(info, tmp, sz, sz, align,
368 + crash_reserved_mem.start,
369 + crash_reserved_mem.end, -1);
372 + * backup segment is after elfcorehdr, so use elfcorehdr as top of
373 + * kernel's available memory
375 + cmdline_add_mem(mod_cmdline, crash_reserved_mem.start,
376 + elfcorehdr - crash_reserved_mem.start);
377 + cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
378 + cmdline_add_savemaxmem(mod_cmdline, saved_max_mem);
382 +int is_crashkernel_mem_reserved(void)
384 + uint64_t start, end;
386 + return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
387 + (start != end) : 0;
390 Index: kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.h
391 ===================================================================
392 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
393 +++ kexec-tools-2.0.1/kexec/arch/mips/crashdump-mips.h 2009-09-27 19:07:26.000000000 +0200
395 +#ifndef CRASHDUMP_MIPS_H
396 +#define CRASHDUMP_MIPS_H
399 +int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
400 + unsigned long max_addr, unsigned long min_base);
402 +#define PAGE_OFFSET 0xa800000000000000ULL
404 +#define PAGE_OFFSET 0x80000000
406 +#define __pa(x) ((unsigned long)(X)& 0x7fffffff)
408 +#define MAXMEM 0x80000000
410 +#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1)
411 +#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2)
413 +#define COMMAND_LINE_SIZE 512
415 +/* Backup Region, First 1M of System RAM. */
416 +#define BACKUP_SRC_START 0x00000000
417 +#define BACKUP_SRC_END 0x000fffff
418 +#define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1)
420 +#endif /* CRASHDUMP_MIPS_H */
421 Index: kexec-tools-2.0.1/kexec/arch/mips/include/arch/options.h
422 ===================================================================
423 --- kexec-tools-2.0.1.orig/kexec/arch/mips/include/arch/options.h 2008-07-15 02:46:43.000000000 +0200
424 +++ kexec-tools-2.0.1/kexec/arch/mips/include/arch/options.h 2009-09-27 19:18:21.000000000 +0200
426 #define KEXEC_ARCH_MIPS_OPTIONS_H
428 #define OPT_ARCH_MAX (OPT_MAX+0)
429 +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
432 +#define OPT_ELF64_CORE (OPT_MAX+1)
433 #define KEXEC_ARCH_OPTIONS \
435 + { "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
437 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
438 +#define OPT_ARCH_MAX (OPT_MAX+2)
440 +#define KEXEC_ARCH_OPTIONS \
443 +#define OPT_ARCH_MAX (OPT_MAX+0)
446 #endif /* KEXEC_ARCH_MIPS_OPTIONS_H */
447 Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-elf-mips.c
448 ===================================================================
449 --- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-elf-mips.c 2008-07-15 02:46:43.000000000 +0200
450 +++ kexec-tools-2.0.1/kexec/arch/mips/kexec-elf-mips.c 2009-09-27 19:16:39.000000000 +0200
452 #include <ip_checksum.h>
453 #include "../../kexec.h"
454 #include "../../kexec-elf.h"
455 +#include "../../kexec-syscall.h"
456 #include "kexec-mips.h"
457 #include <arch/options.h>
458 +#include "crashdump-mips.h"
460 static const int probe_debug = 0;
462 #define BOOTLOADER "kexec"
463 #define MAX_COMMAND_LINE 256
465 -#define UPSZ(X) ((sizeof(X) + 3) & ~3)
466 -static struct boot_notes {
469 - unsigned char bl_desc[UPSZ(BOOTLOADER)];
471 - unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
473 - unsigned char command_line[0];
474 -} elf_boot_notes = {
476 - .b_signature = 0x0E1FB007,
477 - .b_size = sizeof(elf_boot_notes),
483 - .n_descsz = sizeof(BOOTLOADER),
484 - .n_type = EBN_BOOTLOADER_NAME,
486 - .bl_desc = BOOTLOADER,
489 - .n_descsz = sizeof(BOOTLOADER_VERSION),
490 - .n_type = EBN_BOOTLOADER_VERSION,
492 - .blv_desc = BOOTLOADER_VERSION,
496 - .n_type = EBN_COMMAND_LINE,
501 -#define OPT_APPEND (OPT_ARCH_MAX+0)
502 +/* 'kexec' in cmdline is used to find cmdline buffer by kernel */
503 +static char cmdline_buf[256] = "kexec ";
505 int elf_mips_probe(const char *buf, off_t len)
508 struct kexec_info *info)
510 struct mem_ehdr ehdr;
513 - unsigned long arg_base;
514 - struct boot_notes *notes;
516 - const char *command_line;
517 - int command_line_len;
518 - unsigned char *setup_start;
519 - uint32_t setup_size;
520 + unsigned long bss_start, bss_size = 0;
521 + const char *command_line = NULL;
522 + char *modified_cmdline;
523 + int modified_cmdline_len;
524 + unsigned long cmdline_addr;
527 +#define OPT_APPEND (OPT_ARCH_MAX+0)
528 static const struct option options[] = {
530 {"command-line", 1, 0, OPT_APPEND},
531 @@ -144,38 +109,81 @@
535 - command_line_len = 0;
536 - setup_simple_regs.spr9 = 0;
537 - if (command_line) {
538 - command_line_len = strlen(command_line) + 1;
539 - setup_simple_regs.spr9 = 2;
540 + /* Need to append some command line parameters internally in case of
541 + * taking crash dumps.
543 + if (info->kexec_flags & KEXEC_ON_CRASH) {
544 + modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
545 + memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
546 + if (command_line) {
547 + strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE);
548 + modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
550 + modified_cmdline_len = strlen(modified_cmdline);
553 - /* Load the ELF executable */
554 - elf_exec_build_load(info, &ehdr, buf, len, 0);
556 - setup_start = setup_simple_start;
557 - setup_size = setup_simple_size;
558 - setup_simple_regs.spr8 = ehdr.e_entry;
560 - note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
561 - arg_bytes = note_bytes + ((setup_size + 3) & ~3);
563 - arg_buf = xmalloc(arg_bytes);
564 - arg_base = add_buffer_virt(info,
565 - arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1);
566 + /* Parse the Elf file */
567 + result = build_elf_exec_info(buf, len, &ehdr, 0);
569 + die("ELF exec parse failed\n");
572 - notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3));
573 + /* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/
574 + for(i = 0; i < ehdr.e_phnum; i++) {
575 + struct mem_phdr *phdr;
576 + phdr = &ehdr.e_phdr[i];
577 + if (phdr->p_type == PT_LOAD) {
578 + phdr->p_paddr = virt_to_phys(phdr->p_paddr);
582 - memcpy(arg_buf, setup_start, setup_size);
583 - memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
584 - memcpy(notes->command_line, command_line, command_line_len);
585 + for(i = 0; i < ehdr.e_shnum; i++) {
586 + struct mem_shdr *shdr;
587 + unsigned char *strtab;
588 + strtab = (unsigned char *)ehdr.e_shdr[ehdr.e_shstrndx].sh_data;
590 + shdr = &ehdr.e_shdr[i];
591 + if ( shdr->sh_size &&
592 + strcmp((char *)&strtab[shdr->sh_name],
594 + bss_start = virt_to_phys(shdr->sh_addr);
595 + bss_size = shdr->sh_size;
600 - notes->hdr.b_size = note_bytes;
601 - notes->cmd_hdr.n_descsz = command_line_len;
602 - notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
603 + /* Load the Elf data */
604 + result = elf_exec_load(&ehdr, info);
606 + die("ELF exec load failed\n");
608 + info->entry = (void *)virt_to_phys(ehdr.e_entry);
610 + die("No .bss segment present\n");
612 + /* Put cmdline right after bss */
613 + cmdline_addr = bss_start + bss_size;
615 + /* If panic kernel is being loaded, additional segments need
618 + if (info->kexec_flags & KEXEC_ON_CRASH) {
619 + result = load_crashdump_segments(info, modified_cmdline,
623 + /* Use new command line. */
624 + command_line = modified_cmdline;
627 - info->entry = (void *)arg_base;
630 + strncat(cmdline_buf,command_line,
631 + sizeof(cmdline_buf) - strlen(cmdline_buf) - 1);
632 + add_buffer(info, cmdline_buf, sizeof(cmdline_buf),
633 + sizeof(cmdline_buf), sizeof(void*),
634 + cmdline_addr, 0x0fffffff, 1);
639 Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.c
640 ===================================================================
641 --- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-mips.c 2008-07-15 02:46:43.000000000 +0200
642 +++ kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.c 2009-09-27 19:20:25.000000000 +0200
645 void arch_usage(void)
648 + fprintf(stderr, " --elf32-core-headers Prepare core headers in "
654 +struct arch_options_t arch_options = {
655 + .core_header_type = CORE_TYPE_ELF64
659 int arch_process_options(int argc, char **argv)
661 static const struct option options[] = {
667 + case OPT_ELF64_CORE:
668 + arch_options.core_header_type = CORE_TYPE_ELF64;
673 /* Reset getopt for the next pass; called in other source modules */
675 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_MIPS here.
677 { "mips", KEXEC_ARCH_DEFAULT },
678 + /* Not using KEXEC_ARCH_DEFAULT because that will fail
679 + * in the kernel's compat_sys_kexec_load() routine.
681 + { "mips64", KEXEC_ARCH_MIPS },
690 - * Adding a dummy function, so that build on mips will not break.
691 - * Need to implement the actual checking code
693 -int is_crashkernel_mem_reserved(void)
698 unsigned long virt_to_phys(unsigned long addr)
700 - return addr - 0x80000000;
701 + return ((addr)& 0x7fffffff);
705 Index: kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.h
706 ===================================================================
707 --- kexec-tools-2.0.1.orig/kexec/arch/mips/kexec-mips.h 2008-07-15 02:46:43.000000000 +0200
708 +++ kexec-tools-2.0.1/kexec/arch/mips/kexec-mips.h 2009-09-27 19:21:32.000000000 +0200
713 -extern unsigned char setup_simple_start[];
714 -extern uint32_t setup_simple_size;
719 -} setup_simple_regs;
720 +#define MAX_MEMORY_RANGES 64
721 +#define CORE_TYPE_ELF32 1
722 +#define CORE_TYPE_ELF64 2
724 int elf_mips_probe(const char *buf, off_t len);
725 int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
726 struct kexec_info *info);
727 void elf_mips_usage(void);
729 +struct arch_options_t {
730 + int core_header_type;
732 #endif /* KEXEC_MIPS_H */