• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
get_file_size(int f)28 int get_file_size(int f)
29 {
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 {
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  */
main(int argc,char * argv[])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 *) ((uintptr_t) 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 *) ((uintptr_t) start_address + KEXEC_ARM_ATAGS_OFFSET);
150     segment[1].memsz = atag_size;
151 
152     rv = kexec_load(((uintptr_t) 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