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