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