[4/5] load and boot kexec kernel
R Sharada
sharada at in.ibm.com
Thu Apr 14 00:14:43 EST 2005
/*
* loadem: bare-bones load and execute something with kexec
*
* Copyright (C) 2004 - 2005 Milton D Miller II, IBM Corporation
*
* 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.
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <malloc.h>
struct proper_kexec_segment {
void *buf;
size_t bufsz;
size_t mem;
size_t memsz;
};
struct kexec_segment {
void *buf;
size_t bufsz;
void *mem;
size_t memsz;
};
extern void __fix_the_kexec_segment_structures(void);
#include "kexec-syscall.h"
void err(char *what, char *which);
void use(char *why);
#define __str(x) #x
#define str(x) __str(x)
struct proper_kexec_segment seg[KEXEC_MAX_SEGMENTS];
unsigned long entry;
unsigned long flags;
unsigned long mask;
struct stat statbuf[1];
char *myname;
#include <errno.h>
int main(int argc, char *argv[])
{
int f=-1, fd, t, arg;
unsigned long *lp;
char *cp;
void *p;
if (sizeof(struct proper_kexec_segment) != sizeof(struct kexec_segment))
__fix_the_kexec_segment_structures();
myname = argv[0];
for (cp = myname; *cp; cp++)
if (*cp == '/')
myname = cp + 1;
for(;;)
switch (arg = getopt(argc, argv, "a:c:ef:kpr:st:z:48")) {
case 'a': /* at Address */
if (++f >= KEXEC_MAX_SEGMENTS)
use("Maximum number of segments ("
str(KEXEC_MAX_SEGMENT)
") exceeded.\n");
seg[f].mem = strtoul(optarg, NULL, 0);
break;
case 'c': /* Chain previous */
if (f < 1)
use("-c: can not chain first file");
lp = seg[f-1].buf + strtoul(optarg, NULL, 0);
lp[-1] = seg[f].mem; /* Big endian, LE use 0 */
break;
case 'e': /* Entry point */
entry = seg[f].mem + seg[f].memsz;
break;
case 'f': /* load File */
fd = open(optarg, O_RDONLY);
if (fd == -1)
err("open", optarg);
if (fstat(fd, statbuf))
err("stat", optarg);
t = statbuf[0].st_size;
p = realloc(seg[f].buf, seg[f].bufsz + t);
if (!p)
err("malloc", optarg);
seg[f].buf = p;
if (read(fd, seg[f].buf + seg[f].bufsz, t) != t)
err("read", optarg);
close(fd);
seg[f].bufsz += t;
seg[f].memsz += t;
break;
case 'k': /* Kexec now */
kexec_reboot();
break;
case 'p': /* load Panic kernel */
flags |= KEXEC_FLAG_ON_PANIC;
break;
case 's': /* load Stdin */
#define CHUNK 4096
t = 0;
do {
seg[f].bufsz += t;
seg[f].memsz += t;
seg[f].buf = realloc(seg[f].buf,
seg[f].bufsz + CHUNK);
if (!seg[f].buf)
err("realloc","<stdin>");
t = read(0, seg[f].buf + seg[f].bufsz, CHUNK);
} while (t > 0);
seg[f].buf = realloc(seg[f].buf, seg[f].bufsz);
if (!seg[f].buf)
err("realloc","<stdin>");
break;
#undef CHUNK
case '8': /* pad to 8 byte bounary */
case '4': /* pad to 4 byte bounary */
t = arg - '0';
t -= seg[f].bufsz & (t-1);
if (t == arg - '0')
break;
seg[f].buf = realloc(seg[f].buf, seg[f].bufsz + t);
if (!seg[f].buf)
err("malloc", "<align>");
cp = seg[f].buf + seg[f].bufsz;
seg[f].memsz += t;
seg[f].bufsz += t;
while (t--)
*cp++ = 0;
break;
case 'r': /* Round up page size; move this to kernel */
mask = strtoul(optarg, NULL, 0);
if (mask & (mask-1))
use("round value must be a power of 2\n");
mask--; /* convert to a mask */
break;
case 't': /* set architecture Type */
t = strtoul(optarg, NULL, 0);
flags |= t << 16;
break;
case 'z': /* Zero extend segment by bumping memsz */
seg[f].memsz += strtoul(optarg, NULL, 0);
break;
case -1:
if (optind < argc)
use("unexpected option or argument\n");
for (t=0; t <= f; t++) { /* move this to the kernel */
seg[t].memsz += mask;
seg[t].memsz &= ~mask;
}
if (errno = -kexec_load((void *)entry, ++f,
(struct kexec_segment *)seg, flags))
err("kexec", "syscall");
exit(0);
default:
use("unknown option or argument\n");
}
}
/* a bit of user frendliness, while still minimizing library usage for size */
#define eput(s) write(2, s, sizeof(s)-1)
#define vput(s) {for (l=0; s[l]; l++); write(2, s, l);}
void use(char *why)
{
int l;
eput("Usage: ");
vput(myname);
eput(" options\n"
"\t where options are:\n"
"\t-a address start a new segment At address\n"
"\t-c offset at offset in previous segment"
" put a Chain pointer to here\n"
"\t-e assign Entry point here\n"
"\t-f file load a File\n"
"\t-k kexec the new kernel NOW\n"
"\t-p load panic kernel\n"
"\t-r size round up segments memsz to size\n"
"\t-s read from Standard input\n"
"\t-t type set architecture flag to given number\n"
"\t-4 4-byte align size, padding with 0\n"
"\t-8 8-byte align size, padding with 0\n"
"\t-z count zero extend segment by count bytes"
" after all files.\n");
exit(1);
}
#include <errno.h>
#include <string.h>
#define TOP_NIB_SHIFT(x) (8*sizeof(x) - 4)
#define TOP_NIB(x) (x >> TOP_NIB_SHIFT(x))
void err(char *what, char *which)
{
unsigned err = errno;
int l, i;
char erro[2*sizeof(err)+6];
for (l=0; l < 2*sizeof(err); l++, err <<= 4)
if (TOP_NIB(err))
break;
for(i=0; i < 2*sizeof(err) - l; i++, err <<= 4)
erro[i+4] = "0123456789abcdef"[TOP_NIB(err)];
erro[0] = ' ';
erro[1] = '(';
erro[2] = '0';
erro[3] = 'x';
erro[4+i+0] = ')';
erro[4+i+1] = '\n';
erro[4+i+2] = '\0';
err = errno; /* save again before the writes below */
vput(myname);
eput(": ");
vput(what);
eput(" ");
vput(which);
eput(": ");
vput(strerror(err));
vput(erro);
exit(2);
}
More information about the Linuxppc64-dev
mailing list