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  */
get_file_size(int f)29 int get_file_size(int f)
30 {
31     struct stat st;
32     fstat(f, &st);
33     return st.st_size;
34 }
35 
test_kexeccall()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 
usage(void)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  */
main(int argc,char * argv[])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