1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
/*
* uImage support for PowerPC
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <image.h>
#include <getopt.h>
#include <arch/options.h>
#include "../../kexec.h"
#include "kexec-ppc.h"
#include "fixup_dtb.h"
#include <kexec-uImage.h>
/* See options.h -- add any more there, too. */
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
{"command-line", 1, 0, OPT_APPEND},
{"append", 1, 0, OPT_APPEND},
{"dtb", 1, 0, OPT_DTB},
{"reuse-node", 1, 0, OPT_NODES},
{0, 0, 0, 0},
};
static const char short_options[] = KEXEC_ARCH_OPT_STR;
void uImage_ppc_usage(void)
{
printf(
" --command-line=STRING Set the kernel command line to STRING.\n"
" --append=STRING Set the kernel command line to STRING.\n"
" --dtb=<filename> Specify device tree blob file.\n"
" --reuse-node=node Specify nodes which should be taken from /proc/device-tree.\n"
" Can be set multiple times.\n"
);
}
int uImage_ppc_probe(const char *buf, off_t len)
{
return uImage_probe(buf, len, IH_ARCH_PPC);
}
static int ppc_load_bare_bits(int argc, char **argv, const char *buf,
off_t len, struct kexec_info *info, unsigned int load_addr,
unsigned int ep)
{
char *command_line;
int command_line_len;
char *dtb;
unsigned int addr;
unsigned long dtb_addr;
#define FIXUP_ENTRYS (20)
char *fixup_nodes[FIXUP_ENTRYS + 1];
int cur_fixup = 0;
int opt;
int ret;
command_line = NULL;
dtb = NULL;
while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
switch (opt) {
default:
/* Ignore core options */
if (opt < OPT_ARCH_MAX) {
break;
}
case '?':
usage();
return -1;
case OPT_APPEND:
command_line = optarg;
break;
case OPT_DTB:
dtb = optarg;
break;
case OPT_NODES:
if (cur_fixup >= FIXUP_ENTRYS) {
fprintf(stderr, "The number of entries for the fixup is too large\n");
exit(1);
}
fixup_nodes[cur_fixup] = optarg;
cur_fixup++;
break;
}
}
command_line_len = 0;
if (command_line)
command_line_len = strlen(command_line) + 1;
fixup_nodes[cur_fixup] = NULL;
/*
* len contains the length of the whole kernel image except the bss
* section. The 3 MiB should cover it. The purgatory and the dtb are
* allocated from memtop down towards zero so we should never get too
* close to the bss :)
*/
ret = valid_memory_range(info, load_addr, len + 3 * 1024 * 1024);
if (!ret) {
printf("Can't add kernel to addr 0x%08x len %ld\n",
load_addr, len + 3 * 1024 * 1024);
return -1;
}
add_segment(info, buf, len, load_addr, len + 3 * 1024 * 1024);
if (dtb) {
char *blob_buf;
off_t blob_size = 0;
/* Grab device tree from buffer */
blob_buf = slurp_file(dtb, &blob_size);
if (!blob_buf || !blob_size)
die("Device tree seems to be an empty file.\n");
blob_buf = fixup_dtb_nodes(blob_buf, &blob_size, fixup_nodes, command_line);
dtb_addr = add_buffer(info, blob_buf, blob_size, blob_size, 0, 0,
KERNEL_ACCESS_TOP, -1);
} else {
dtb_addr = 0;
}
elf_rel_build_load(info, &info->rhdr, (const char *)purgatory,
purgatory_size, 0, -1, -1, 0);
/* set various variables for the purgatory */
addr = ep;
elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr));
addr = dtb_addr;
elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr));
addr = rmo_top;
elf_rel_set_symbol(&info->rhdr, "mem_size", &addr, sizeof(addr));
#define PUL_STACK_SIZE (16 * 1024)
addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, -1, 1);
addr += PUL_STACK_SIZE;
elf_rel_set_symbol(&info->rhdr, "pul_stack", &addr, sizeof(addr));
/* No allocation past here in order not to overwrite the stack */
#undef PUL_STACK_SIZE
addr = elf_rel_get_addr(&info->rhdr, "purgatory_start");
info->entry = (void *)addr;
return 0;
}
int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct Image_info img;
int ret;
ret = uImage_load(buf, len, &img);
if (ret)
return ret;
return ppc_load_bare_bits(argc, argv, img.buf, img.len, info,
img.base, img.ep);
}
|