blob: 0beef89731c9874d5f4a3611ddf8210f90cbed6b [file] [log] [blame]
Szymon Starzycki3d86b012013-07-15 15:17:07 -07001#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 <sys/stat.h>
8#include <sys/syscall.h>
9#include <sys/types.h>
10#include <sys/wait.h>
11#include <unistd.h>
12
13#include "kexec.h"
14
15// Offsets same as in kernel asm/kexec.h
16#define KEXEC_ARM_ATAGS_OFFSET 0x1000
17#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
18
19#define MEMORY_SIZE 0x0800000
20// Physical buffer address cannot overlap with other regions
21#define START_ADDRESS 0x44000000
22
23#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))
24
25/*
26 * Gives file position and resets current position to begining of file
27 */
28int get_file_size(int f)
29{
30 struct stat st;
31 fstat(f, &st);
32 return st.st_size;
33}
34
35int test_kexeccall() {
36 int rv;
37
38 rv = kexec_load(0, 0, NULL, KEXEC_ARCH_DEFAULT);
39
40 if (rv != 0) {
41 printf("ERROR: kexec_load: %d \n", errno);
42 return 1;
43 }
44
45 printf("Kexec test: Success \n");
46
47 return 0;
48}
49
50void usage(void)
51{
52 fprintf(stderr,
53 "usage: kexecload [ <option> ] <atags path> <kernel path>\n"
54 "\n"
55 "options:\n"
56 " -t tests syscall\n"
57 " -s <start address> specify start address of kernel\n"
58 );
59}
60
61/*
62 * Loads kexec into the kernel and sets kexec on crash
63 */
64int main(int argc, char *argv[])
65{
66 int rv;
67 int atag_file,
68 zimage_file;
69 int atag_size,
70 zimage_size,
71 total_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 int option_index = 0;
88 c = getopt_long(argc, argv, "s:th", longopts, NULL);
89 if (c < 0) {
90 break;
91 }
92 /* Alphabetical cases */
93 switch (c) {
94 case 's':
95 start_address = (void *) strtoul(optarg, 0, 16);
96 break;
97 case 'h':
98 usage();
99 return 1;
100 case 't':
101 test_kexeccall();
102 return 1;
103 case '?':
104 return 1;
105 default:
106 abort();
107 }
108 }
109
110 argc -= optind;
111 argv += optind;
112
113 if (argc < 2) {
114 usage();
115 return 1;
116 }
117
118 atag_file = open(argv[0], O_RDONLY);
119 zimage_file = open(argv[1], O_RDONLY);
120
121 if (atag_file < 0 || zimage_file < 0) {
122 fprintf(stderr, "Error during opening of atag file or the zImage file %s\n", strerror(errno));
123 return 1;
124 }
125
126 atag_size = ROUND_TO_PAGE(get_file_size(atag_file), page_size);
127 zimage_size = ROUND_TO_PAGE(get_file_size(zimage_file), page_size);
128
129 if (atag_size >= KEXEC_ARM_ZIMAGE_OFFSET - KEXEC_ARM_ATAGS_OFFSET) {
130 fprintf(stderr, "Atag file is too large\n");
131 return 1;
132 }
133
134 atag_buffer = (char *) mmap(NULL, atag_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, atag_file, 0);
135 zimage_buffer = (char *) mmap(NULL, zimage_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, zimage_file, 0);
136
137 if(atag_buffer == MAP_FAILED || zimage_buffer == MAP_FAILED) {
138 fprintf(stderr, "Unable to map files into memory");
139 return 1;
140 }
141
142 segment[0].buf = zimage_buffer;
143 segment[0].bufsz = zimage_size;
Colin Cross1070ada2014-02-05 18:57:04 -0800144 segment[0].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET);
Szymon Starzycki3d86b012013-07-15 15:17:07 -0700145 segment[0].memsz = zimage_size;
146
147 segment[1].buf = atag_buffer;
148 segment[1].bufsz = atag_size;
Colin Cross1070ada2014-02-05 18:57:04 -0800149 segment[1].mem = (void *) ((uintptr_t) start_address + KEXEC_ARM_ATAGS_OFFSET);
Szymon Starzycki3d86b012013-07-15 15:17:07 -0700150 segment[1].memsz = atag_size;
151
Colin Cross1070ada2014-02-05 18:57:04 -0800152 rv = kexec_load(((uintptr_t) start_address + KEXEC_ARM_ZIMAGE_OFFSET),
Szymon Starzycki3d86b012013-07-15 15:17:07 -0700153 2, (void *) segment, KEXEC_ARCH_DEFAULT | KEXEC_ON_CRASH);
154
155 if (rv != 0) {
156 fprintf(stderr, "Kexec_load returned non-zero exit code: %d with errno %d\n", rv, errno);
157 return 1;
158 }
159
160 printf("Done! Kexec loaded\n");
161 printf("New kernel should start at 0x%08x\n", START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET);
162
163 return 0;
164
165}
166