1 --- a/kexec/arch/mips/Makefile
2 +++ b/kexec/arch/mips/Makefile
4 mips_KEXEC_SRCS = kexec/arch/mips/kexec-mips.c
5 mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-mips.c
6 mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-rel-mips.c
7 -mips_KEXEC_SRCS += kexec/arch/mips/mips-setup-simple.S
8 +mips_KEXEC_SRCS += kexec/arch/mips/crashdump-mips.c
13 +++ b/kexec/arch/mips/crashdump-mips.c
16 + * kexec: Linux boots Linux
18 + * 2005 (C) IBM Corporation.
19 + * 2008 (C) MontaVista Software, Inc.
21 + * This program is free software; you can redistribute it and/or modify
22 + * it under the terms of the GNU General Public License as published by
23 + * the Free Software Foundation (version 2 of the License).
25 + * This program is distributed in the hope that it will be useful,
26 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 + * GNU General Public License for more details.
30 + * You should have received a copy of the GNU General Public License
31 + * along with this program; if not, write to the Free Software
32 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
39 +#include <sys/types.h>
40 +#include <sys/stat.h>
42 +#include "../../kexec.h"
43 +#include "../../kexec-elf.h"
44 +#include "../../kexec-syscall.h"
45 +#include "../../crashdump.h"
46 +#include "kexec-mips.h"
47 +#include "crashdump-mips.h"
49 +extern struct arch_options_t arch_options;
51 +/* Stores a sorted list of RAM memory ranges for which to create elf headers.
52 + * A separate program header is created for backup region */
53 +static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES];
55 +/* Memory region reserved for storing panic kernel and other data. */
56 +static struct memory_range crash_reserved_mem;
59 + * To store the memory size of the first kernel and this value will be
60 + * passed to the second kernel as command line (savemaxmem=xM).
61 + * The second kernel will be calculated saved_max_pfn based on this
64 +unsigned long long saved_max_mem = 0;
66 +/* Removes crash reserve region from list of memory chunks for whom elf program
67 + * headers have to be created. Assuming crash reserve region to be a single
68 + * continuous area fully contained inside one of the memory chunks */
69 +static int exclude_crash_reserve_region(int *nr_ranges)
71 + int i, j, tidx = -1;
72 + unsigned long long cstart, cend;
73 + struct memory_range temp_region;
75 + /* Crash reserved region. */
76 + cstart = crash_reserved_mem.start;
77 + cend = crash_reserved_mem.end;
79 + for (i = 0; i < (*nr_ranges); i++) {
80 + unsigned long long mstart, mend;
81 + mstart = crash_memory_range[i].start;
82 + mend = crash_memory_range[i].end;
83 + if (cstart < mend && cend > mstart) {
84 + if (cstart != mstart && cend != mend) {
85 + /* Split memory region */
86 + crash_memory_range[i].end = cstart - 1;
87 + temp_region.start = cend + 1;
88 + temp_region.end = mend;
89 + temp_region.type = RANGE_RAM;
91 + } else if (cstart != mstart)
92 + crash_memory_range[i].end = cstart - 1;
94 + crash_memory_range[i].start = cend + 1;
97 + /* Insert split memory region, if any. */
99 + if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) {
100 + /* No space to insert another element. */
101 + fprintf(stderr, "Error: Number of crash memory ranges"
102 + " excedeed the max limit\n");
105 + for (j = (*nr_ranges - 1); j >= tidx; j--)
106 + crash_memory_range[j+1] = crash_memory_range[j];
107 + crash_memory_range[tidx].start = temp_region.start;
108 + crash_memory_range[tidx].end = temp_region.end;
109 + crash_memory_range[tidx].type = temp_region.type;
114 +/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
115 + * create Elf headers. Keeping it separate from get_memory_ranges() as
116 + * requirements are different in the case of normal kexec and crashdumps.
118 + * Normal kexec needs to look at all of available physical memory irrespective
119 + * of the fact how much of it is being used by currently running kernel.
120 + * Crashdumps need to have access to memory regions actually being used by
121 + * running kernel. Expecting a different file/data structure than /proc/iomem
122 + * to look into down the line. May be something like /proc/kernelmem or may
123 + * be zone data structures exported from kernel.
125 +static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
127 + const char iomem[]= "/proc/iomem";
128 + int i, memory_ranges = 0;
129 + char line[MAX_LINE];
131 + unsigned long long start, end;
133 + fp = fopen(iomem, "r");
135 + fprintf(stderr, "Cannot open %s: %s\n",
136 + iomem, strerror(errno));
140 + /* Separate segment for backup region */
141 + crash_memory_range[0].start = BACKUP_SRC_START;
142 + crash_memory_range[0].end = BACKUP_SRC_END;
143 + crash_memory_range[0].type = RANGE_RAM;
146 + while(fgets(line, sizeof(line), fp) != 0) {
148 + int type, consumed, count;
149 + if (memory_ranges >= CRASH_MAX_MEMORY_RANGES)
151 + count = sscanf(line, "%Lx-%Lx : %n",
152 + &start, &end, &consumed);
155 + str = line + consumed;
157 + /* Only Dumping memory of type System RAM. */
158 + if (memcmp(str, "System RAM\n", 11) == 0) {
160 + } else if (memcmp(str, "Crash kernel\n", 13) == 0) {
161 + /* Reserved memory region. New kernel can
162 + * use this region to boot into. */
163 + crash_reserved_mem.start = start;
164 + crash_reserved_mem.end = end;
165 + crash_reserved_mem.type = RANGE_RAM;
171 + if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1))
172 + start = BACKUP_SRC_END + 1;
174 + crash_memory_range[memory_ranges].start = start;
175 + crash_memory_range[memory_ranges].end = end;
176 + crash_memory_range[memory_ranges].type = type;
179 + /* Segregate linearly mapped region. */
180 + if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) {
181 + crash_memory_range[memory_ranges-1].end = MAXMEM -1;
183 + /* Add segregated region. */
184 + crash_memory_range[memory_ranges].start = MAXMEM;
185 + crash_memory_range[memory_ranges].end = end;
186 + crash_memory_range[memory_ranges].type = type;
192 + if (exclude_crash_reserve_region(&memory_ranges) < 0)
195 + for (i = 0; i < memory_ranges; i++)
196 + if (saved_max_mem < crash_memory_range[i].end)
197 + saved_max_mem = crash_memory_range[i].end + 1;
199 + *range = crash_memory_range;
200 + *ranges = memory_ranges;
204 +/* Converts unsigned long to ascii string. */
205 +static void ultoa(unsigned long i, char *str)
211 + str[j++] = i % 10 + '0';
212 + } while ((i /=10) > 0);
215 + /* Reverse the string. */
216 + for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
223 +/* Adds the appropriate mem= options to command line, indicating the
224 + * memory region the new kernel can use to boot into. */
225 +static int cmdline_add_mem(char *cmdline, unsigned long addr, unsigned long size)
228 + char str[50], *ptr;
233 + strcpy (str, " mem=");
234 + ptr += strlen(str);
236 + strcat (str, "K@");
237 + ptr = str + strlen(str);
241 + cmdlen = strlen(cmdline) + len;
242 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
243 + die("Command line overflow\n");
244 + strcat(cmdline, str);
249 +/* Adds the elfcorehdr= command line parameter to command line. */
250 +static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr)
252 + int cmdlen, len, align = 1024;
253 + char str[30], *ptr;
255 + /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline.
256 + * Ensure 1K alignment*/
261 + strcpy(str, " elfcorehdr=");
262 + ptr += strlen(str);
266 + cmdlen = strlen(cmdline) + len;
267 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
268 + die("Command line overflow\n");
269 + strcat(cmdline, str);
273 +/* Adds the elfcorehdr= command line parameter to command line. */
274 +static int cmdline_add_savemaxmem(char *cmdline, unsigned long addr)
276 + int cmdlen, len, align = 1024;
277 + char str[30], *ptr;
279 + /* Passing in savemaxmem=xxxM format. Saves space required in cmdline.*/
280 + addr = addr/(align*align);
282 + strcpy(str, " savemaxmem=");
283 + ptr += strlen(str);
287 + cmdlen = strlen(cmdline) + len;
288 + if (cmdlen > (COMMAND_LINE_SIZE - 1))
289 + die("Command line overflow\n");
290 + strcat(cmdline, str);
295 +static struct crash_elf_info elf_info64 =
300 + backup_src_start: BACKUP_SRC_START,
301 + backup_src_end: BACKUP_SRC_END,
302 + page_offset: PAGE_OFFSET,
303 + lowmem_limit: MAXMEM,
306 +static struct crash_elf_info elf_info32 =
311 + backup_src_start: BACKUP_SRC_START,
312 + backup_src_end: BACKUP_SRC_END,
313 + page_offset: PAGE_OFFSET,
314 + lowmem_limit: MAXMEM,
317 +/* Loads additional segments in case of a panic kernel is being loaded.
318 + * One segment for backup region, another segment for storing elf headers
319 + * for crash memory image.
321 +int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
322 + unsigned long max_addr, unsigned long min_base)
325 + unsigned long sz, elfcorehdr;
326 + int nr_ranges, align = 1024;
327 + struct memory_range *mem_range;
329 + if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
332 + /* Create a backup region segment to store backup data*/
333 + sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
335 + memset(tmp, 0, sz);
336 + info->backup_start = add_buffer(info, tmp, sz, sz, align,
337 + crash_reserved_mem.start,
338 + crash_reserved_mem.end,-1);
341 + /* Create elf header segment and store crash image data. */
342 + if (arch_options.core_header_type == CORE_TYPE_ELF64) {
343 + if (crash_create_elf64_headers(info, &elf_info64,
344 + crash_memory_range, nr_ranges,
346 + ELF_CORE_HEADER_ALIGN) < 0)
350 + if (crash_create_elf32_headers(info, &elf_info32,
351 + crash_memory_range, nr_ranges,
353 + ELF_CORE_HEADER_ALIGN) < 0)
357 + if (crash_create_elf32_headers(info, &elf_info32,
358 + crash_memory_range, nr_ranges,
360 + ELF_CORE_HEADER_ALIGN) < 0)
363 + elfcorehdr = add_buffer(info, tmp, sz, sz, align,
364 + crash_reserved_mem.start,
365 + crash_reserved_mem.end, -1);
368 + * backup segment is after elfcorehdr, so use elfcorehdr as top of
369 + * kernel's available memory
371 + cmdline_add_mem(mod_cmdline, crash_reserved_mem.start,
372 + elfcorehdr - crash_reserved_mem.start);
373 + cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr);
374 + cmdline_add_savemaxmem(mod_cmdline, saved_max_mem);
378 +int is_crashkernel_mem_reserved(void)
380 + uint64_t start, end;
382 + return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
383 + (start != end) : 0;
387 +++ b/kexec/arch/mips/crashdump-mips.h
389 +#ifndef CRASHDUMP_MIPS_H
390 +#define CRASHDUMP_MIPS_H
393 +int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
394 + unsigned long max_addr, unsigned long min_base);
396 +#define PAGE_OFFSET 0xa800000000000000ULL
398 +#define PAGE_OFFSET 0x80000000
400 +#define __pa(x) ((unsigned long)(X)& 0x7fffffff)
402 +#define MAXMEM 0x80000000
404 +#define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1)
405 +#define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2)
407 +#define COMMAND_LINE_SIZE 512
409 +/* Backup Region, First 1M of System RAM. */
410 +#define BACKUP_SRC_START 0x00000000
411 +#define BACKUP_SRC_END 0x000fffff
412 +#define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1)
414 +#endif /* CRASHDUMP_MIPS_H */
415 --- a/kexec/arch/mips/include/arch/options.h
416 +++ b/kexec/arch/mips/include/arch/options.h
418 #define KEXEC_ARCH_MIPS_OPTIONS_H
420 #define OPT_ARCH_MAX (OPT_MAX+0)
421 +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
424 +#define OPT_ELF64_CORE (OPT_MAX+1)
425 #define KEXEC_ARCH_OPTIONS \
427 + { "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \
429 #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
430 +#define OPT_ARCH_MAX (OPT_MAX+2)
432 +#define KEXEC_ARCH_OPTIONS \
435 +#define OPT_ARCH_MAX (OPT_MAX+0)
438 #endif /* KEXEC_ARCH_MIPS_OPTIONS_H */
439 --- a/kexec/arch/mips/kexec-elf-mips.c
440 +++ b/kexec/arch/mips/kexec-elf-mips.c
442 #include <ip_checksum.h>
443 #include "../../kexec.h"
444 #include "../../kexec-elf.h"
445 +#include "../../kexec-syscall.h"
446 #include "kexec-mips.h"
447 #include <arch/options.h>
448 +#include "crashdump-mips.h"
450 static const int probe_debug = 0;
452 #define BOOTLOADER "kexec"
453 #define MAX_COMMAND_LINE 256
455 -#define UPSZ(X) ((sizeof(X) + 3) & ~3)
456 -static struct boot_notes {
459 - unsigned char bl_desc[UPSZ(BOOTLOADER)];
461 - unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
463 - unsigned char command_line[0];
464 -} elf_boot_notes = {
466 - .b_signature = 0x0E1FB007,
467 - .b_size = sizeof(elf_boot_notes),
473 - .n_descsz = sizeof(BOOTLOADER),
474 - .n_type = EBN_BOOTLOADER_NAME,
476 - .bl_desc = BOOTLOADER,
479 - .n_descsz = sizeof(BOOTLOADER_VERSION),
480 - .n_type = EBN_BOOTLOADER_VERSION,
482 - .blv_desc = BOOTLOADER_VERSION,
486 - .n_type = EBN_COMMAND_LINE,
491 -#define OPT_APPEND (OPT_ARCH_MAX+0)
492 +/* 'kexec' in cmdline is used to find cmdline buffer by kernel */
493 +static char cmdline_buf[256] = "kexec ";
495 int elf_mips_probe(const char *buf, off_t len)
497 @@ -108,16 +75,14 @@ int elf_mips_load(int argc, char **argv,
498 struct kexec_info *info)
500 struct mem_ehdr ehdr;
503 - unsigned long arg_base;
504 - struct boot_notes *notes;
506 - const char *command_line;
507 - int command_line_len;
508 - unsigned char *setup_start;
509 - uint32_t setup_size;
510 + unsigned long bss_start, bss_size = 0;
511 + const char *command_line = NULL;
512 + char *modified_cmdline;
513 + int modified_cmdline_len;
514 + unsigned long cmdline_addr;
517 +#define OPT_APPEND (OPT_ARCH_MAX+0)
518 static const struct option options[] = {
520 {"command-line", 1, 0, OPT_APPEND},
521 @@ -144,38 +109,81 @@ int elf_mips_load(int argc, char **argv,
525 - command_line_len = 0;
526 - setup_simple_regs.spr9 = 0;
527 - if (command_line) {
528 - command_line_len = strlen(command_line) + 1;
529 - setup_simple_regs.spr9 = 2;
530 + /* Need to append some command line parameters internally in case of
531 + * taking crash dumps.
533 + if (info->kexec_flags & KEXEC_ON_CRASH) {
534 + modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
535 + memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
536 + if (command_line) {
537 + strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE);
538 + modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
540 + modified_cmdline_len = strlen(modified_cmdline);
543 - /* Load the ELF executable */
544 - elf_exec_build_load(info, &ehdr, buf, len, 0);
546 - setup_start = setup_simple_start;
547 - setup_size = setup_simple_size;
548 - setup_simple_regs.spr8 = ehdr.e_entry;
550 - note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
551 - arg_bytes = note_bytes + ((setup_size + 3) & ~3);
553 - arg_buf = xmalloc(arg_bytes);
554 - arg_base = add_buffer_virt(info,
555 - arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1);
556 + /* Parse the Elf file */
557 + result = build_elf_exec_info(buf, len, &ehdr, 0);
559 + die("ELF exec parse failed\n");
562 - notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3));
563 + /* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/
564 + for(i = 0; i < ehdr.e_phnum; i++) {
565 + struct mem_phdr *phdr;
566 + phdr = &ehdr.e_phdr[i];
567 + if (phdr->p_type == PT_LOAD) {
568 + phdr->p_paddr = virt_to_phys(phdr->p_paddr);
572 - memcpy(arg_buf, setup_start, setup_size);
573 - memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
574 - memcpy(notes->command_line, command_line, command_line_len);
575 + for(i = 0; i < ehdr.e_shnum; i++) {
576 + struct mem_shdr *shdr;
577 + unsigned char *strtab;
578 + strtab = (unsigned char *)ehdr.e_shdr[ehdr.e_shstrndx].sh_data;
580 + shdr = &ehdr.e_shdr[i];
581 + if ( shdr->sh_size &&
582 + strcmp((char *)&strtab[shdr->sh_name],
584 + bss_start = virt_to_phys(shdr->sh_addr);
585 + bss_size = shdr->sh_size;
590 - notes->hdr.b_size = note_bytes;
591 - notes->cmd_hdr.n_descsz = command_line_len;
592 - notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
593 + /* Load the Elf data */
594 + result = elf_exec_load(&ehdr, info);
596 + die("ELF exec load failed\n");
598 + info->entry = (void *)virt_to_phys(ehdr.e_entry);
600 + die("No .bss segment present\n");
602 + /* Put cmdline right after bss */
603 + cmdline_addr = bss_start + bss_size;
605 + /* If panic kernel is being loaded, additional segments need
608 + if (info->kexec_flags & KEXEC_ON_CRASH) {
609 + result = load_crashdump_segments(info, modified_cmdline,
613 + /* Use new command line. */
614 + command_line = modified_cmdline;
617 - info->entry = (void *)arg_base;
620 + strncat(cmdline_buf,command_line,
621 + sizeof(cmdline_buf) - strlen(cmdline_buf) - 1);
622 + add_buffer(info, cmdline_buf, sizeof(cmdline_buf),
623 + sizeof(cmdline_buf), sizeof(void*),
624 + cmdline_addr, 0x0fffffff, 1);
629 --- a/kexec/arch/mips/kexec-mips.c
630 +++ b/kexec/arch/mips/kexec-mips.c
631 @@ -97,8 +97,18 @@ int file_types = sizeof(file_type) / siz
633 void arch_usage(void)
636 + fprintf(stderr, " --elf32-core-headers Prepare core headers in "
642 +struct arch_options_t arch_options = {
643 + .core_header_type = CORE_TYPE_ELF64
647 int arch_process_options(int argc, char **argv)
649 static const struct option options[] = {
650 @@ -113,6 +123,11 @@ int arch_process_options(int argc, char
655 + case OPT_ELF64_CORE:
656 + arch_options.core_header_type = CORE_TYPE_ELF64;
661 /* Reset getopt for the next pass; called in other source modules */
662 @@ -126,6 +141,10 @@ const struct arch_map_entry arches[] = {
663 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_MIPS here.
665 { "mips", KEXEC_ARCH_DEFAULT },
666 + /* Not using KEXEC_ARCH_DEFAULT because that will fail
667 + * in the kernel's compat_sys_kexec_load() routine.
669 + { "mips64", KEXEC_ARCH_MIPS },
673 @@ -138,18 +157,9 @@ void arch_update_purgatory(struct kexec_
678 - * Adding a dummy function, so that build on mips will not break.
679 - * Need to implement the actual checking code
681 -int is_crashkernel_mem_reserved(void)
686 unsigned long virt_to_phys(unsigned long addr)
688 - return addr - 0x80000000;
689 + return ((addr)& 0x7fffffff);
693 --- a/kexec/arch/mips/kexec-mips.h
694 +++ b/kexec/arch/mips/kexec-mips.h
699 -extern unsigned char setup_simple_start[];
700 -extern uint32_t setup_simple_size;
705 -} setup_simple_regs;
706 +#define MAX_MEMORY_RANGES 64
707 +#define CORE_TYPE_ELF32 1
708 +#define CORE_TYPE_ELF64 2
710 int elf_mips_probe(const char *buf, off_t len);
711 int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
712 struct kexec_info *info);
713 void elf_mips_usage(void);
715 +struct arch_options_t {
716 + int core_header_type;
718 #endif /* KEXEC_MIPS_H */