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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
/*
* kexec/arch/s390/kexec-image.c
*
* (C) Copyright IBM Corp. 2005
*
* Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <getopt.h>
#include "../../kexec.h"
#include "../../kexec-syscall.h"
#include "../../kexec/crashdump.h"
#include "kexec-s390.h"
#include <arch/options.h>
#include <fcntl.h>
static uint64_t crash_base, crash_end;
static void add_segment_check(struct kexec_info *info, const void *buf,
size_t bufsz, unsigned long base, size_t memsz)
{
if (info->kexec_flags & KEXEC_ON_CRASH)
if (base + memsz > crash_end - crash_base)
die("Not enough crashkernel memory to load segments\n");
add_segment(info, buf, bufsz, crash_base + base, memsz);
}
int command_line_add(struct kexec_info *info, const char *str)
{
char *tmp = NULL;
tmp = concat_cmdline(info->command_line, str);
if (!tmp) {
fprintf(stderr, "out of memory\n");
return -1;
}
free(info->command_line);
info->command_line = tmp;
return 0;
}
int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
{
const char *ramdisk = NULL;
int opt;
static const struct option options[] =
{
KEXEC_ALL_OPTIONS
{0, 0, 0, 0},
};
static const char short_options[] = KEXEC_OPT_STR "";
while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch(opt) {
case OPT_APPEND:
if (command_line_add(info, optarg))
return -1;
break;
case OPT_RAMDISK:
ramdisk = optarg;
break;
case OPT_REUSE_CMDLINE:
free(info->command_line);
info->command_line = get_command_line();
break;
}
}
if (ramdisk) {
info->initrd_fd = open(ramdisk, O_RDONLY);
if (info->initrd_fd == -1) {
fprintf(stderr, "Could not open initrd file %s:%s\n",
ramdisk, strerror(errno));
free(info->command_line);
info->command_line = NULL;
return -1;
}
}
if (info->command_line)
info->command_line_len = strlen(info->command_line) + 1;
else
info->command_line_len = 0;
return 0;
}
int
image_s390_load(int argc, char **argv, const char *kernel_buf,
off_t kernel_size, struct kexec_info *info)
{
void *krnl_buffer;
char *rd_buffer;
const char *ramdisk;
off_t ramdisk_len;
unsigned int ramdisk_origin;
int opt, ret = -1;
if (info->file_mode)
return image_s390_load_file(argc, argv, info);
static const struct option options[] =
{
KEXEC_ALL_OPTIONS
{0, 0, 0, 0},
};
static const char short_options[] = KEXEC_OPT_STR "";
ramdisk = NULL;
ramdisk_len = 0;
ramdisk_origin = 0;
while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) {
switch(opt) {
case OPT_APPEND:
if (command_line_add(info, optarg))
return -1;
break;
case OPT_REUSE_CMDLINE:
free(info->command_line);
info->command_line = get_command_line();
break;
case OPT_RAMDISK:
ramdisk = optarg;
break;
}
}
if (info->kexec_flags & KEXEC_ON_CRASH) {
if (parse_iomem_single("Crash kernel\n", &crash_base,
&crash_end))
goto out;
}
/* Add kernel segment */
add_segment_check(info, kernel_buf + IMAGE_READ_OFFSET,
kernel_size - IMAGE_READ_OFFSET, IMAGE_READ_OFFSET,
kernel_size - IMAGE_READ_OFFSET);
/* We do want to change the kernel image */
krnl_buffer = (void *) kernel_buf + IMAGE_READ_OFFSET;
/*
* Load ramdisk if present: If image is larger than RAMDISK_ORIGIN_ADDR,
* we load the ramdisk directly behind the image with 1 MiB alignment.
*/
if (ramdisk) {
rd_buffer = slurp_file_mmap(ramdisk, &ramdisk_len);
if (rd_buffer == NULL) {
fprintf(stderr, "Could not read ramdisk.\n");
goto out;
}
ramdisk_origin = MAX(RAMDISK_ORIGIN_ADDR, kernel_size);
ramdisk_origin = _ALIGN_UP(ramdisk_origin, 0x100000);
add_segment_check(info, rd_buffer, ramdisk_len,
ramdisk_origin, ramdisk_len);
}
if (info->kexec_flags & KEXEC_ON_CRASH) {
if (load_crashdump_segments(info, crash_base, crash_end))
goto out;
} else {
info->entry = (void *) IMAGE_READ_OFFSET;
}
/* Register the ramdisk and crashkernel memory in the kernel. */
{
unsigned long long *tmp;
tmp = krnl_buffer + INITRD_START_OFFS;
*tmp = (unsigned long long) ramdisk_origin;
tmp = krnl_buffer + INITRD_SIZE_OFFS;
*tmp = (unsigned long long) ramdisk_len;
if (info->kexec_flags & KEXEC_ON_CRASH) {
tmp = krnl_buffer + OLDMEM_BASE_OFFS;
*tmp = crash_base;
tmp = krnl_buffer + OLDMEM_SIZE_OFFS;
*tmp = crash_end - crash_base + 1;
}
}
if (info->command_line) {
unsigned long maxsize;
char *dest = krnl_buffer + COMMAND_LINE_OFFS;
maxsize = *(unsigned long *)(krnl_buffer + MAX_COMMAND_LINESIZE_OFFS);
if (!maxsize)
maxsize = LEGACY_COMMAND_LINESIZE;
if (strlen(info->command_line) > maxsize-1) {
fprintf(stderr, "command line too long, maximum allowed size %ld\n",
maxsize-1);
goto out;
}
strncpy(dest, info->command_line, maxsize-1);
dest[maxsize-1] = '\0';
}
ret = 0;
out:
free(info->command_line);
info->command_line = NULL;
return ret;
}
int
image_s390_probe(const char *UNUSED(kernel_buf), off_t UNUSED(kernel_size))
{
/*
* Can't reliably tell if an image is valid,
* therefore everything is valid.
*/
return 0;
}
void
image_s390_usage(void)
{
printf("--command-line=STRING Set the kernel command line to STRING.\n"
"--append=STRING Set the kernel command line to STRING.\n"
"--initrd=FILENAME Use the file FILENAME as a ramdisk.\n"
"--reuse-cmdline Use kernel command line from running system.\n"
);
}
|