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
|
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "kexec.h"
// Offsets same as in kernel asm/kexec.h
#define KEXEC_ARM_ATAGS_OFFSET 0x1000
#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
#define MEMORY_SIZE 0x0800000
// Physical buffer address cannot overlap with other regions
#define START_ADDRESS 0x44000000
#define ROUND_TO_PAGE(address,pagesize) (((address) + (pagesize) - 1) & (~((pagesize) - 1)))
/*
* Gives file position and resets current position to begining of file
*/
int get_file_size(int f)
{
struct stat st;
fstat(f, &st);
return st.st_size;
}
int test_kexeccall() {
int rv;
rv = kexec_load(0, 0, NULL, KEXEC_ARCH_DEFAULT);
if (rv != 0) {
printf("ERROR: kexec_load: %d \n", errno);
return 1;
}
printf("Kexec test: Success \n");
return 0;
}
void usage(void)
{
fprintf(stderr,
"usage: kexecload [ <option> ] <atags path> <kernel path>\n"
"\n"
"options:\n"
" -t tests syscall\n"
" -s <start address> specify start address of kernel\n"
);
}
/*
* Loads kexec into the kernel and sets kexec on crash
*/
int main(int argc, char *argv[])
{
int rv;
int atag_file,
zimage_file;
int atag_size,
zimage_size;
void *atag_buffer;
void *zimage_buffer;
struct kexec_segment segment[2];
int page_size = getpagesize();
void *start_address = (void *)START_ADDRESS;
int c;
const struct option longopts[] = {
{"start_address", required_argument, 0, 's'},
{"test", 0, 0, 't'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
while (1) {
c = getopt_long(argc, argv, "s:th", longopts, NULL);
if (c < 0) {
break;
}
/* Alphabetical cases */
switch (c) {
case 's':
start_address = (void *) strtoul(optarg, 0, 16);
break;
case 'h':
usage();
return 1;
case 't':
test_kexeccall();
return 1;
case '?':
return 1;
default:
abort();
}
}
argc -= optind;
argv += optind;
if (argc < 2) {
usage();
return 1;
}
atag_file = open(argv[0], O_RDONLY);
zimage_file = open(argv[1], O_RDONLY);
if (atag_file < 0 || zimage_file < 0) {
fprintf(stderr, "Error during opening of atag file or the zImage file %s\n", strerror(errno));
return 1;
}
atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size);
zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size);
if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) {
fprintf(stderr, "Atag file is too large\n");
return 1;
}
atag_buffer = (char *) mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0);
zimage_buffer = (char *) mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0);
if(atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) {
fprintf(stderr, "Unable to map files into memory");
return 1;
}
segment[0].buf = zimage_buffer;
segment[0].bufsz = zimage_size;
segment[0].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET);
segment[0].memsz = zimage_size;
segment[1].buf = atag_buffer;
segment[1].bufsz = atag_size;
segment[1].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ATAGS_OFFSET);
segment[1].memsz = atag_size;
rv = kexec_load(((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET),
2, (void *) segment, KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH);
if (rv != 0) {
fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno);
return 1;
}
printf("Done! Kexec loaded\n");
printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET);
return 0;
}
|