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 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 c = getopt_long(argc, argv, "s:th", longopts, NULL); 88 if (c < 0) { 89 break; 90 } 91 /* Alphabetical cases */ 92 switch (c) { 93 case 's': 94 start_address = (void *) strtoul(optarg, 0, 16); 95 break; 96 case 'h': 97 usage(); 98 return 1; 99 case 't': 100 test_kexeccall(); 101 return 1; 102 case '?': 103 return 1; 104 default: 105 abort(); 106 } 107 } 108 109 argc -= optind; 110 argv += optind; 111 112 if (argc < 2) { 113 usage(); 114 return 1; 115 } 116 117 atag_file = open(argv[0], O_RDONLY); 118 zimage_file = open(argv[1], O_RDONLY); 119 120 if (atag_file < 0 || zimage_file < 0) { 121 fprintf(stderr, "Error during opening of atag file or the zImage file %s\n", strerror(errno)); 122 return 1; 123 } 124 125 atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size); 126 zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size); 127 128 if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) { 129 fprintf(stderr, "Atag file is too large\n"); 130 return 1; 131 } 132 133 atag_buffer = (char *) mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0); 134 zimage_buffer = (char *) mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0); 135 136 if(atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) { 137 fprintf(stderr, "Unable to map files into memory"); 138 return 1; 139 } 140 141 segment[0].buf = zimage_buffer; 142 segment[0].bufsz = zimage_size; 143 segment[0].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET); 144 segment[0].memsz = zimage_size; 145 146 segment[1].buf = atag_buffer; 147 segment[1].bufsz = atag_size; 148 segment[1].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ATAGS_OFFSET); 149 segment[1].memsz = atag_size; 150 151 rv = kexec_load(((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET), 152 2, (void *) segment, KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH); 153 154 if (rv != 0) { 155 fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno); 156 return 1; 157 } 158 159 printf("Done! Kexec loaded\n"); 160 printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET); 161 162 return 0; 163 164 } 165 166