1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
/*
* kexec: Linux boots Linux
*
* Copyright (C) 2008 Magnus Damm
*
* Based on x86 implementation,
* Copyright (C) 2003-2005 Eric Biederman (ebiederm@xmission.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation (version 2 of the License).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <elf.h>
#include "../../kexec.h"
#include "../../kexec-syscall.h"
#include "../../kexec-elf.h"
#include "../../kexec-elf-boot.h"
#include <arch/options.h>
#include "crashdump-sh.h"
#include "kexec-sh.h"
int elf_sh_probe(const char *buf, off_t len)
{
struct mem_ehdr ehdr;
int result;
result = build_elf_exec_info(buf, len, &ehdr, 0);
if (result < 0)
goto out;
/* Verify the architecuture specific bits */
if (ehdr.e_machine != EM_SH) {
result = -1;
goto out;
}
result = 0;
out:
free_elf_info(&ehdr);
return result;
}
void elf_sh_usage(void)
{
printf(" --append=STRING Set the kernel command line to STRING\n"
);
}
int elf_sh_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct mem_ehdr ehdr;
char *command_line;
char *modified_cmdline;
struct mem_sym sym;
int opt, rc;
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
{ 0, 0, 0, 0 },
};
static const char short_options[] = KEXEC_OPT_STR "";
/*
* Parse the command line arguments
*/
command_line = modified_cmdline = 0;
while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
default:
/* Ignore core options */
if (opt < OPT_ARCH_MAX) {
break;
}
case '?':
usage();
return -1;
case OPT_APPEND:
command_line = optarg;
break;
}
}
/* Need to append some command line parameters internally in case of
* taking crash dumps.
*/
if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
if (command_line) {
strncpy(modified_cmdline, command_line,
COMMAND_LINE_SIZE);
modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
}
}
/* Load the ELF executable */
elf_exec_build_load(info, &ehdr, buf, len, 0);
info->entry = (void *)virt_to_phys(ehdr.e_entry);
/* If panic kernel is being loaded, additional segments need
* to be created. */
if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
rc = load_crashdump_segments(info, modified_cmdline);
if (rc < 0)
return -1;
/* Use new command line. */
command_line = modified_cmdline;
}
/* If we're booting a vmlinux then fill in empty_zero_page */
if (elf_rel_find_symbol(&ehdr, "empty_zero_page", &sym) == 0) {
char *zp = (void *)ehdr.e_shdr[sym.st_shndx].sh_data;
kexec_sh_setup_zero_page(zp, 4096, command_line);
}
return 0;
}
|