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