• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <getopt.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/mman.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     struct stat st;
31     fstat(f, &st);
32     return st.st_size;
33 }
34 
test_kexeccall()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 
usage(void)50 void usage(void) {
51     fprintf(stderr,
52             "usage: kexecload [ <option> ] <atags path> <kernel path>\n"
53             "\n"
54             "options:\n"
55             "  -t                                       tests syscall\n"
56             "  -s <start address>                       specify start address of kernel\n");
57 }
58 
59 /*
60  * Loads kexec into the kernel and sets kexec on crash
61  */
main(int argc,char * argv[])62 int main(int argc, char* argv[]) {
63     int rv;
64     int atag_file, zimage_file;
65     int atag_size, zimage_size;
66     void* atag_buffer;
67     void* zimage_buffer;
68     struct kexec_segment segment[2];
69     int page_size = getpagesize();
70     void* start_address = (void*)START_ADDRESS;
71     int c;
72 
73     const struct option longopts[] = {{"start_address", required_argument, 0, 's'},
74                                       {"test", 0, 0, 't'},
75                                       {"help", 0, 0, 'h'},
76                                       {0, 0, 0, 0}};
77 
78     while (1) {
79         c = getopt_long(argc, argv, "s:th", longopts, NULL);
80         if (c < 0) {
81             break;
82         }
83         /* Alphabetical cases */
84         switch (c) {
85             case 's':
86                 start_address = (void*)strtoul(optarg, 0, 16);
87                 break;
88             case 'h':
89                 usage();
90                 return 1;
91             case 't':
92                 test_kexeccall();
93                 return 1;
94             case '?':
95                 return 1;
96             default:
97                 abort();
98         }
99     }
100 
101     argc -= optind;
102     argv += optind;
103 
104     if (argc < 2) {
105         usage();
106         return 1;
107     }
108 
109     atag_file = open(argv[0], O_RDONLY);
110     zimage_file = open(argv[1], O_RDONLY);
111 
112     if (atag_file < 0 || zimage_file < 0) {
113         fprintf(stderr, "Error during opening of atag file or the zImage file %s\n",
114                 strerror(errno));
115         return 1;
116     }
117 
118     atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size);
119     zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size);
120 
121     if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) {
122         fprintf(stderr, "Atag file is too large\n");
123         return 1;
124     }
125 
126     atag_buffer = (char*)mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0);
127     zimage_buffer =
128             (char*)mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0);
129 
130     if (atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) {
131         fprintf(stderr, "Unable to map files into memory");
132         return 1;
133     }
134 
135     segment[0].buf = zimage_buffer;
136     segment[0].bufsz = zimage_size;
137     segment[0].mem = (void*)((uintptr_t)start_address + KEXEC_ARM_ZIMAGE_OFFSET);
138     segment[0].memsz = zimage_size;
139 
140     segment[1].buf = atag_buffer;
141     segment[1].bufsz = atag_size;
142     segment[1].mem = (void*)((uintptr_t)start_address + KEXEC_ARM_ATAGS_OFFSET);
143     segment[1].memsz = atag_size;
144 
145     rv = kexec_load(((uintptr_t)start_address + KEXEC_ARM_ZIMAGE_OFFSET), 2, (void*)segment,
146                     KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH);
147 
148     if (rv != 0) {
149         fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno);
150         return 1;
151     }
152 
153     printf("Done! Kexec loaded\n");
154     printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET);
155 
156     return 0;
157 }
158