190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin#include "defs.h"
290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin#include <linux/kexec.h>
390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
40ed617bd66624cec6138102545d73b2e2346f1f6Dmitry V. Levin#include "xlat/kexec_arch_values.h"
50ed617bd66624cec6138102545d73b2e2346f1f6Dmitry V. Levin#include "xlat/kexec_flags.h"
690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levinstatic void
890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levinprint_kexec_segments(struct tcb *tcp, unsigned long addr, unsigned long len)
990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin{
1090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin#if SUPPORTED_PERSONALITIES > 1
1190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	union {
1290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		struct { u_int32_t buf, bufsz, mem, memsz; } seg32;
1390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		struct { u_int64_t buf, bufsz, mem, memsz; } seg64;
1490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	} seg;
1590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define sizeof_seg \
1690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	(current_wordsize == 4 ? sizeof(seg.seg32) : sizeof(seg.seg64))
1790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define seg_buf \
1890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	(current_wordsize == 4 ? (uint64_t) seg.seg32.buf : seg.seg64.buf)
1990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define seg_bufsz \
2090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	(current_wordsize == 4 ? (uint64_t) seg.seg32.bufsz : seg.seg64.bufsz)
2190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define seg_mem \
2290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	(current_wordsize == 4 ? (uint64_t) seg.seg32.mem : seg.seg64.mem)
2390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define seg_memsz \
2490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	(current_wordsize == 4 ? (uint64_t) seg.seg32.memsz : seg.seg64.memsz)
2590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin#else
2690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	struct kexec_segment seg;
2790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin# define sizeof_seg sizeof(seg)
28900ec1b0428b1ba2676d00b8c7cc4b0f9a89c543Dmitry V. Levin# define seg_buf seg.buf
29900ec1b0428b1ba2676d00b8c7cc4b0f9a89c543Dmitry V. Levin# define seg_bufsz seg.bufsz
30900ec1b0428b1ba2676d00b8c7cc4b0f9a89c543Dmitry V. Levin# define seg_mem seg.mem
31900ec1b0428b1ba2676d00b8c7cc4b0f9a89c543Dmitry V. Levin# define seg_memsz seg.memsz
3290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin#endif
3390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	unsigned int i, failed;
3490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
3590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	if (!len) {
3690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		tprints("[]");
3790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		return;
3890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	}
3990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
4090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	if (len > KEXEC_SEGMENT_MAX) {
4190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		tprintf("%#lx", addr);
4290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		return;
4390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	}
4490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
4590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	failed = 0;
4690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	tprints("[");
4790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	for (i = 0; i < len; ++i) {
4890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		if (i)
4990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			tprints(", ");
5090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		if (umoven(tcp, addr + i * sizeof_seg, sizeof_seg,
5190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			   (char *) &seg) < 0) {
5290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			tprints("?");
5390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			failed = 1;
5490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			break;
5590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		}
5690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		tprintf("{%#lx, %lu, %#lx, %lu}",
5790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			(long) seg_buf, (unsigned long) seg_bufsz,
5890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin			(long) seg_mem, (unsigned long) seg_memsz);
5990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	}
6090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	tprints("]");
6190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	if (failed)
6290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		tprintf(" %#lx", addr);
6390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin}
6490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
6590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levinint
6690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levinsys_kexec_load(struct tcb *tcp)
6790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin{
6890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	unsigned long n;
6990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
7090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	if (exiting(tcp))
7190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		return 0;
7290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
7390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	/* entry, nr_segments */
7490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
7590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
7690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	/* segments */
7790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	print_kexec_segments(tcp, tcp->u_arg[2], tcp->u_arg[1]);
7890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	tprints(", ");
7990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
8090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	/* flags */
8190aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	n = tcp->u_arg[3];
8290aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	printxval(kexec_arch_values, n & KEXEC_ARCH_MASK, "KEXEC_ARCH_???");
8390aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	n &= ~KEXEC_ARCH_MASK;
8490aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	if (n) {
8590aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		tprints("|");
8690aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin		printflags(kexec_flags, n, "KEXEC_???");
8790aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	}
8890aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin
8990aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin	return 0;
9090aa9f4d72e26581ea0a39c02db625d7bd4e2962Dmitry V. Levin}
91