Home | History | Annotate | Download | only in kexec_tools
      1 #include <errno.h>
      2 #include <getopt.h>
      3 #include <fcntl.h>
      4 #include <sys/mman.h>
      5 #include <stdlib.h>
      6 #include <stdio.h>
      7 #include <sys/stat.h>
      8 #include <sys/syscall.h>
      9 #include <sys/types.h>
     10 #include <sys/wait.h>
     11 #include <unistd.h>
     12 
     13 #include "kexec.h"
     14 
     15 // Offsets same as in kernel asm/kexec.h
     16 #define KEXEC_ARM_ATAGS_OFFSET  0x1000
     17 #define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
     18 
     19 #define MEMORY_SIZE 0x0800000
     20 // Physical buffer address cannot overlap with other regions
     21 #define START_ADDRESS 0x44000000
     22 
     23 #define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))
     24 
     25 /*
     26  * Gives file position and resets current position to begining of file
     27  */
     28 int get_file_size(int f)
     29 {
     30     struct stat st;
     31     fstat(f, &st);
     32     return st.st_size;
     33 }
     34 
     35 int test_kexeccall() {
     36     int rv;
     37 
     38     rv = kexec_load(0, 0, NULL, KEXEC_ARCH_DEFAULT);
     39 
     40     if (rv != 0) {
     41         printf("ERROR: kexec_load: %d \n", errno);
     42         return 1;
     43     }
     44 
     45     printf("Kexec test: Success \n");
     46 
     47     return 0;
     48 }
     49 
     50 void usage(void)
     51 {
     52     fprintf(stderr,
     53             "usage: kexecload [ <option> ] <atags path> <kernel path>\n"
     54             "\n"
     55             "options:\n"
     56             "  -t                                       tests syscall\n"
     57             "  -s <start address>                       specify start address of kernel\n"
     58         );
     59 }
     60 
     61 /*
     62  * Loads kexec into the kernel and sets kexec on crash
     63  */
     64 int main(int argc, char *argv[])
     65 {
     66     int rv;
     67     int atag_file,
     68         zimage_file;
     69     int atag_size,
     70         zimage_size,
     71         total_size;
     72     void *atag_buffer;
     73     void *zimage_buffer;
     74     struct kexec_segment segment[2];
     75     int page_size = getpagesize();
     76     void *start_address = (void *)START_ADDRESS;
     77     int c;
     78 
     79     const struct option longopts[] = {
     80         {"start_address", required_argument, 0, 's'},
     81         {"test", 0, 0, 't'},
     82         {"help", 0, 0, 'h'},
     83         {0, 0, 0, 0}
     84     };
     85 
     86     while (1) {
     87         int option_index = 0;
     88         c = getopt_long(argc, argv, "s:th", longopts, NULL);
     89         if (c < 0) {
     90             break;
     91         }
     92         /* Alphabetical cases */
     93         switch (c) {
     94         case 's':
     95             start_address = (void *) strtoul(optarg, 0, 16);
     96             break;
     97         case 'h':
     98             usage();
     99             return 1;
    100         case 't':
    101             test_kexeccall();
    102             return 1;
    103         case '?':
    104             return 1;
    105         default:
    106             abort();
    107         }
    108     }
    109 
    110     argc -= optind;
    111     argv += optind;
    112 
    113     if (argc < 2) {
    114         usage();
    115         return 1;
    116     }
    117 
    118     atag_file = open(argv[0], O_RDONLY);
    119     zimage_file = open(argv[1], O_RDONLY);
    120 
    121     if (atag_file < 0 || zimage_file < 0) {
    122         fprintf(stderr, "Error during opening of atag file or the zImage file %s\n", strerror(errno));
    123         return 1;
    124     }
    125 
    126     atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size);
    127     zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size);
    128 
    129     if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) {
    130         fprintf(stderr, "Atag file is too large\n");
    131         return 1;
    132     }
    133 
    134     atag_buffer = (char *) mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0);
    135     zimage_buffer = (char *) mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0);
    136 
    137     if(atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) {
    138         fprintf(stderr, "Unable to map files into memory");
    139         return 1;
    140     }
    141 
    142     segment[0].buf = zimage_buffer;
    143     segment[0].bufsz = zimage_size;
    144     segment[0].mem = (void *) ((unsigned) start_address + KEXEC_ARM_ZIMAGE_OFFSET);
    145     segment[0].memsz = zimage_size;
    146 
    147     segment[1].buf = atag_buffer;
    148     segment[1].bufsz = atag_size;
    149     segment[1].mem = (void *) ((unsigned) start_address + KEXEC_ARM_ATAGS_OFFSET);
    150     segment[1].memsz = atag_size;
    151 
    152     rv = kexec_load(((unsigned) start_address + KEXEC_ARM_ZIMAGE_OFFSET),
    153                     2, (void *) segment, KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH);
    154 
    155     if (rv != 0) {
    156         fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno);
    157         return 1;
    158     }
    159 
    160     printf("Done! Kexec loaded\n");
    161     printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET);
    162 
    163     return 0;
    164 
    165 }
    166 
    167