aboutsummaryrefslogtreecommitdiff
path: root/util/mkelfImage/linux-ia64/convert_params.c
blob: a58f4adf801026762c889022ee7188f8de16a444 (plain)
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#include "stdint.h"
#include "limits.h"
#include <stdarg.h>
#include "elf.h"
#include "elf_boot.h"
#include "convert.h"


/* NOTE be very careful with static variables.  No relocations are
 * being performed so static variables with initialized pointers will
 * point to the wrong locations, unless this file is loaded at just
 * the right location.
 */
/* Data and functions in head.S */
extern void uart_tx_byte(int c);

static void putchar(int c)
{
	if (c == '\n') {
		putchar('\r');
	}
#if 0
	uart_tx_byte(c);
#endif
}

#define LONG_SHIFT  ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
#define INT_SHIFT   ((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
#define SHRT_SHIFT  ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
#define CHAR_SHIFT  ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))

/**************************************************************************
PRINTF and friends

	Formats:
		%x	- 4 bytes int (8 hex digits, lower case)
		%X	- 4 bytes int (8 hex digits, upper case)
		%lx     - 8 bytes long (16 hex digits, lower case)
		%lX     - 8 bytes long (16 hex digits, upper case)
		%hx	- 2 bytes int (4 hex digits, lower case)
		%hX	- 2 bytes int (4 hex digits, upper case)
		%hhx	- 1 byte int (2 hex digits, lower case)
		%hhX	- 1 byte int (2 hex digits, upper case)
			- optional # prefixes 0x or 0X
		%d	- decimal int
		%c	- char
		%s	- string
	Note: width specification not supported
**************************************************************************/
static void printf(const char *fmt, ...)
{
	va_list args;
	char *p;
	va_start(args, fmt);
	for ( ; *fmt != '\0'; ++fmt) {
		if (*fmt != '%') {
			putchar(*fmt);
			continue;
		}
		if (*++fmt == 's') {
			for(p = va_arg(args, char *); *p != '\0'; p++)
				putchar(*p);
		}
		else {	/* Length of item is bounded */
			char tmp[40], *q = tmp;
			int shift = INT_SHIFT;
			if (*fmt == 'l') {
				shift = LONG_SHIFT;
				fmt++;
			}
			else if (*fmt == 'h') {
				shift = SHRT_SHIFT;
				fmt++;
				if (*fmt == 'h') {
					shift = CHAR_SHIFT;
					fmt++;
				}
			}

			/*
			 * Before each format q points to tmp buffer
			 * After each format q points past end of item
			 */
			if ((*fmt | 0x20) == 'x') {
				/* With x86 gcc, sizeof(long) == sizeof(int) */
				unsigned long h;
				int ncase;
				if (shift > INT_SHIFT) {
					h = va_arg(args, unsigned long);
				} else {
					h = va_arg(args, unsigned int);
				}
				ncase = (*fmt & 0x20);
				for ( ; shift >= 0; shift -= 4)
					*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
			}
			else if (*fmt == 'd') {
				char *r;
				long i;
				if (shift > INT_SHIFT) {
					i = va_arg(args, long);
				} else {
					i = va_arg(args, int);
				}
				if (i < 0) {
					*q++ = '-';
					i = -i;
				}
				p = q;		/* save beginning of digits */
				do {
					*q++ = '0' + (i % 10);
					i /= 10;
				} while (i);
				/* reverse digits, stop in middle */
				r = q;		/* don't alter q */
				while (--r > p) {
					i = *r;
					*r = *p;
					*p++ = i;
				}
			}
			else if (*fmt == 'c')
				*q++ = va_arg(args, int);
			else
				*q++ = *fmt;
			/* now output the saved string */
			for (p = tmp; p < q; ++p)
				putchar(*p);
		}
	}
	va_end(args);
}

void *memcpy(void *vdest, void *vsrc, size_t size)
{
	unsigned char *dest = vdest, *src = vsrc;
	size_t i;
	for(i = 0; i < size; i++) {
		*dest++ = *src++;
	}
	return dest;
}

int memcmp(void *vs1, void *vs2, size_t size)
{
	unsigned char *s1 =vs1, *s2=vs2;
	size_t i;
	for(i = 0; i < size; i++, s1++, s2++) {
		if (*s1 != *s2)
			return *s1 - *s2;
	}
	return 0;

}

void strappend(char *dest, const char *src, size_t max)
{
	size_t len, i;
	/* Walk to the end of the destination string */
	for(len = 0; len < max; len++) {
		if (dest[len] == '\0')
			break;
	}
	/* Walk through the source string and append it */
	for(i = 0; (i + len) < max; i++) {
		if (src[i] == '\0')
			break;
		dest[len + i] = src[i];
	}
	len = len + i;
	/* Now null terminate the string */
	if (len >= max) {
		len = max -1;
	}
	dest[len] = '\0';
}

static struct ia64_boot_param {
	uint64_t command_line;		/* physical address of command line arguments */
	uint64_t efi_systab;		/* physical address of EFI system table */
	uint64_t efi_memmap;		/* physical address of EFI memory map */
	uint64_t efi_memmap_size;		/* size of EFI memory map */
	uint64_t efi_memdesc_size;		/* size of an EFI memory map descriptor */
	uint32_t efi_memdesc_version;	/* memory descriptor version */
	struct {
		uint16_t num_cols;	/* number of columns on console output device */
		uint16_t num_rows;	/* number of rows on console output device */
		uint16_t orig_x;	/* cursor's x position */
		uint16_t orig_y;	/* cursor's y position */
	} console_info;
	uint64_t fpswa;		/* physical address of the fpswa interface */
	uint64_t initrd_start;
	uint64_t initrd_size;
} bp = { 0, 0, 0, 0, 0, 0, { 80, 24, 0, 0 }, 0, 0, 0 };

static void append_command_line(char *arg)
{
	strappend((char *)bp.command_line, " ", CMDLINE_MAX);
	strappend((char *)bp.command_line, arg, CMDLINE_MAX);
}

static void convert_ia64_boot_params(struct ia64_boot_param *orig_bp)
{
	/* Copy the parameters I have no clue about */
	bp.efi_systab            = orig_bp->efi_systab;
	bp.efi_memmap            = orig_bp->efi_memmap;
	bp.efi_memmap_size       = orig_bp->efi_memmap_size;
	bp.efi_memdesc_size      = orig_bp->efi_memdesc_size;
	bp.efi_memdesc_version   = orig_bp->efi_memdesc_version;
	bp.console_info.num_cols = orig_bp->console_info.num_cols;
	bp.console_info.num_rows = orig_bp->console_info.num_rows;
	bp.console_info.orig_x   = orig_bp->console_info.orig_x;
	bp.console_info.orig_y   = orig_bp->console_info.orig_y;
	bp.fpswa                 = orig_bp->fpswa;
	/* If a ramdisk was supplied and I didn't original have one,
	 * use it.
	 */
	if (orig_bp->initrd_size && (!bp.initrd_size)) {
		bp.initrd_start = orig_bp->initrd_start;
		bp.initrd_size = orig_bp->initrd_size;
	}
	/* If a command line was supplied append it */
	if (orig_bp->command_line) {
		append_command_line((char *)(orig_bp->command_line));
	}
}

static void convert_bhdr_params(Elf_Bhdr *bhdr)
{
	unsigned char *note, *end;
	char *ldr_name, *ldr_version, *firmware;

	ldr_name = ldr_version = firmware = 0;

	note = ((char *)bhdr) + sizeof(*bhdr);
	end  = ((char *)bhdr) + bhdr->b_size;
	while(note < end) {
		Elf_Nhdr *hdr;
		unsigned char *n_name, *n_desc, *next;
		hdr = (Elf_Nhdr *)note;
		n_name = note + sizeof(*hdr);
		n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
		next = n_desc + ((hdr->n_descsz + 3) & ~3);
		if (next > end)
			break;
#if 0
		printf("n_type: %x n_name(%d): n_desc(%d): \n",
			hdr->n_type, hdr->n_namesz, hdr->n_descsz);
#endif

		if (hdr->n_namesz == 0) {
			switch(hdr->n_type) {
			case EBN_FIRMWARE_TYPE:
				firmware = n_desc;
				break;
			case EBN_BOOTLOADER_NAME:
				ldr_name = n_desc;
				break;
			case EBN_BOOTLOADER_VERSION:
				ldr_version = n_desc;
				break;
			case EBN_COMMAND_LINE:
				append_command_line(n_desc);
				break;
			}
		}
		else if ((hdr->n_namesz == 10) &&
			(memcmp(n_name, "Etherboot", 10) == 0)) {
			switch(hdr->n_type) {
			case EB_IA64_SYSTAB:
			{
				uint64_t *systabp = (void *)n_desc;
				bp.efi_systab = *systabp;
				break;
			}
			case EB_IA64_FPSWA:
			{
				uint64_t *fpswap = (void *)n_desc;
				bp.fpswa = *fpswap;
				break;
			}
			case EB_IA64_CONINFO:
				memcpy(&bp.console_info, n_desc, sizeof(bp.console_info));
				break;
			case EB_IA64_MEMMAP:
			{
				struct efi_mem_map {
					uint64_t	map_size;
					uint64_t        map_key;
					uint64_t        descriptor_size;
					uint64_t        descriptor_version;
					uint8_t         map[40];
				} *map = (void *)n_desc;
				bp.efi_memmap = (uint64_t)&map->map;
				bp.efi_memmap_size     = map->map_size;
				bp.efi_memdesc_size    = map->descriptor_size;
				bp.efi_memdesc_version = map->descriptor_version;
				break;
			}
			}
		}
		note = next;
	}
	if (ldr_name && ldr_version) {
		printf("Loader: %s version: %s\n",
			ldr_name, ldr_version);
	}
	if (firmware) {
		printf("Firmware: %s\n",
			firmware);
	}
}

void *convert_params(unsigned long arg1, unsigned long r28,
	struct image_parameters *params)
{
	struct ia64_boot_param *orig_bp;
	Elf_Bhdr *bhdr = (Elf_Bhdr*)arg1;

	/* handle the options I can easily deal with */
	bp.command_line = (unsigned long)&params->cmdline;
	bp.initrd_start = params->initrd_start;
	bp.initrd_size  = params->initrd_size;

	orig_bp = (struct ia64_boot_param *)r28;
	if (bhdr->b_signature == 0x0E1FB007) {
		convert_bhdr_params(bhdr);
	}
	else {
		convert_ia64_boot_params(orig_bp);
	}

	return &bp;
}