You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.2 KiB
167 lines
4.2 KiB
#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, |
|
total_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) { |
|
int option_index = 0; |
|
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; |
|
|
|
} |
|
|
|
|