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