13d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <errno.h> 23d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <getopt.h> 33d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <fcntl.h> 43d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <sys/mman.h> 53d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <stdlib.h> 63d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <stdio.h> 78678c6fc0a7c2f29f1843cc3d0be23cc5908fa85Elliott Hughes#include <string.h> 83d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <sys/stat.h> 93d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <sys/syscall.h> 103d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <sys/types.h> 113d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <sys/wait.h> 123d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include <unistd.h> 133d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 143d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#include "kexec.h" 153d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 163d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki// Offsets same as in kernel asm/kexec.h 173d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#define KEXEC_ARM_ATAGS_OFFSET 0x1000 183d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000 193d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 203d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#define MEMORY_SIZE 0x0800000 213d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki// Physical buffer address cannot overlap with other regions 223d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki#define START_ADDRESS 0x44000000 233d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 24622710626cdc59b472a4993036406790636f1036Chih-Hung Hsieh#define ROUND_TO_PAGE(address,pagesize) (((address) + (pagesize) - 1) & (~((pagesize) - 1))) 253d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 263d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki/* 273d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki * Gives file position and resets current position to begining of file 283d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki */ 293d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzyckiint get_file_size(int f) 303d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki{ 313d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki struct stat st; 323d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fstat(f, &st); 333d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return st.st_size; 343d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki} 353d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 363d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzyckiint test_kexeccall() { 373d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int rv; 383d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 393d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki rv = kexec_load(0, 0, NULL, KEXEC_ARCH_DEFAULT); 403d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 413d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (rv != 0) { 423d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki printf("ERROR: kexec_load: %d \n", errno); 433d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 443d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 453d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 463d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki printf("Kexec test: Success \n"); 473d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 483d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 0; 493d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki} 503d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 513d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzyckivoid usage(void) 523d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki{ 533d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fprintf(stderr, 543d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki "usage: kexecload [ <option> ] <atags path> <kernel path>\n" 553d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki "\n" 563d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki "options:\n" 573d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki " -t tests syscall\n" 583d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki " -s <start address> specify start address of kernel\n" 593d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki ); 603d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki} 613d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 623d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki/* 633d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki * Loads kexec into the kernel and sets kexec on crash 643d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki */ 653d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzyckiint main(int argc, char *argv[]) 663d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki{ 673d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int rv; 683d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int atag_file, 693d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki zimage_file; 703d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int atag_size, 713d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki zimage_size, 723d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki total_size; 733d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki void *atag_buffer; 743d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki void *zimage_buffer; 753d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki struct kexec_segment segment[2]; 763d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int page_size = getpagesize(); 773d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki void *start_address = (void *)START_ADDRESS; 783d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int c; 793d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 803d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki const struct option longopts[] = { 813d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki {"start_address", required_argument, 0, 's'}, 823d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki {"test", 0, 0, 't'}, 833d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki {"help", 0, 0, 'h'}, 843d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki {0, 0, 0, 0} 853d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki }; 863d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 873d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki while (1) { 883d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki int option_index = 0; 893d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki c = getopt_long(argc, argv, "s:th", longopts, NULL); 903d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (c < 0) { 913d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki break; 923d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 933d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki /* Alphabetical cases */ 943d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki switch (c) { 953d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki case 's': 963d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki start_address = (void *) strtoul(optarg, 0, 16); 973d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki break; 983d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki case 'h': 993d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki usage(); 1003d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1013d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki case 't': 1023d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki test_kexeccall(); 1033d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1043d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki case '?': 1053d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1063d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki default: 1073d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki abort(); 1083d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1093d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1103d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1113d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki argc -= optind; 1123d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki argv += optind; 1133d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1143d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (argc < 2) { 1153d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki usage(); 1163d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1173d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1183d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1193d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki atag_file = open(argv[0], O_RDONLY); 1203d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki zimage_file = open(argv[1], O_RDONLY); 1213d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1223d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (atag_file < 0 || zimage_file < 0) { 1233d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fprintf(stderr, "Error during opening of atag file or the zImage file %s\n", strerror(errno)); 1243d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1253d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1263d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1273d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size); 1283d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size); 1293d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1303d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) { 1313d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fprintf(stderr, "Atag file is too large\n"); 1323d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1333d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1343d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1353d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki atag_buffer = (char *) mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0); 1363d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki zimage_buffer = (char *) mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0); 1373d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1383d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if(atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) { 1393d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fprintf(stderr, "Unable to map files into memory"); 1403d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1413d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1423d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1433d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[0].buf = zimage_buffer; 1443d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[0].bufsz = zimage_size; 1451070ada9d23531e494167fe81a81f9f1b82aaa21Colin Cross segment[0].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET); 1463d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[0].memsz = zimage_size; 1473d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1483d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[1].buf = atag_buffer; 1493d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[1].bufsz = atag_size; 1501070ada9d23531e494167fe81a81f9f1b82aaa21Colin Cross segment[1].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ATAGS_OFFSET); 1513d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki segment[1].memsz = atag_size; 1523d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1531070ada9d23531e494167fe81a81f9f1b82aaa21Colin Cross rv = kexec_load(((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET), 1543d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 2, (void *) segment, KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH); 1553d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1563d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki if (rv != 0) { 1573d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno); 1583d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 1; 1593d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki } 1603d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1613d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki printf("Done! Kexec loaded\n"); 1623d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET); 1633d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1643d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki return 0; 1653d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 1663d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki} 1673d86b018b6e08a84af214206ebedf342a8576a91Szymon Starzycki 168