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