~ft/kexec-tools

74c68b80b85b7a1e9cca3ada0952d8f7b9bb3858 — Sigrid Solveig Haflínudóttir 1 year, 2 months ago 70bf934 + db26ac7 plan9
Merge remote-tracking branch 'upstream/main' into plan9
M .github/workflows/build.yml => .github/workflows/build.yml +3 -1
@@ 61,7 61,9 @@ jobs:

    - name: Install Dependencies
      if: env.EXTRA_PKGS != ''
      run: sudo apt-get -q=2 install ${{ env.EXTRA_PKGS }}
      run: |
        sudo apt-get update
        sudo apt-get -q=2 install ${{ env.EXTRA_PKGS }}

    - name: Build
      run: |

M configure.ac => configure.ac +1 -1
@@ 4,7 4,7 @@ dnl
dnl 

dnl ---Required
AC_INIT(kexec-tools, 2.0.23)
AC_INIT(kexec-tools, 2.0.24.git)
AC_CONFIG_AUX_DIR(./config)
AC_CONFIG_HEADERS([include/config.h])
AC_LANG(C)

M kexec/arch/arm64/crashdump-arm64.c => kexec/arch/arm64/crashdump-arm64.c +38 -43
@@ 27,11 27,11 @@
static struct memory_ranges system_memory_rgns;

/* memory range reserved for crashkernel */
struct memory_range crash_reserved_mem;
struct memory_range crash_reserved_mem[CRASH_MAX_RESERVED_RANGES];
struct memory_ranges usablemem_rgns = {
	.size = 0,
	.max_size = 1,
	.ranges = &crash_reserved_mem,
	.max_size = CRASH_MAX_RESERVED_RANGES,
	.ranges = crash_reserved_mem,
};

struct memory_range elfcorehdr_mem;


@@ 47,27 47,6 @@ static struct crash_elf_info elf_info = {
};

/*
 * Note: The returned value is correct only if !CONFIG_RANDOMIZE_BASE.
 */
static uint64_t get_kernel_page_offset(void)
{
	int i;

	if (elf_info.kern_vaddr_start == UINT64_MAX)
		return UINT64_MAX;

	/* Current max virtual memory range is 48-bits. */
	for (i = 48; i > 0; i--)
		if (!(elf_info.kern_vaddr_start & (1UL << i)))
			break;

	if (i <= 0)
		return UINT64_MAX;
	else
		return UINT64_MAX << i;
}

/*
 * iomem_range_callback() - callback called for each iomem region
 * @data: not used
 * @nr: not used


@@ 91,14 70,22 @@ static int iomem_range_callback(void *UNUSED(data), int UNUSED(nr),
		return mem_regions_alloc_and_add(&system_memory_rgns,
						base, length, RANGE_RAM);
	else if (strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) == 0) {

		unsigned long long  kva_text = get_kernel_sym("_text");
		unsigned long long  kva_stext = get_kernel_sym("_stext");
		unsigned long long  kva_text_end = get_kernel_sym("__init_begin");

		/*
		 * old: kernel_code.start   = __pa_symbol(_text);
		 * new: kernel_code.start   = __pa_symbol(_stext);
		 *
		 * By utilizing the fact that paddr(_text) should align on 2MB, plus
		 * _stext - _text <= 64K.
		 * For compatibility, deduce by comparing the gap "__init_begin - _stext"
		 * and the res size of "Kernel code" in /proc/iomem
		 */
		elf_info.kern_paddr_start = base & ((0xffffffffffffffffUL) << 21);
		if (kva_text_end - kva_stext == length)
			elf_info.kern_paddr_start = base - (kva_stext - kva_text);
		else
			elf_info.kern_paddr_start = base;
	}
	else if (strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) == 0)
		elf_info.kern_size = base + length - elf_info.kern_paddr_start;


@@ 111,7 98,7 @@ int is_crashkernel_mem_reserved(void)
	if (!usablemem_rgns.size)
		kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);

	return crash_reserved_mem.start != crash_reserved_mem.end;
	return usablemem_rgns.size;
}

/*


@@ 125,6 112,8 @@ int is_crashkernel_mem_reserved(void)
 */
static int crash_get_memory_ranges(void)
{
	int i;

	/*
	 * First read all memory regions that can be considered as
	 * system memory including the crash area.


@@ 132,16 121,19 @@ static int crash_get_memory_ranges(void)
	if (!usablemem_rgns.size)
		kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);

	/* allow only a single region for crash dump kernel */
	if (usablemem_rgns.size != 1)
	/* allow one or two regions for crash dump kernel */
	if (!usablemem_rgns.size)
		return -EINVAL;

	dbgprint_mem_range("Reserved memory range", &crash_reserved_mem, 1);
	dbgprint_mem_range("Reserved memory range",
			usablemem_rgns.ranges, usablemem_rgns.size);

	if (mem_regions_alloc_and_exclude(&system_memory_rgns,
						&crash_reserved_mem)) {
		fprintf(stderr, "Cannot allocate memory for ranges\n");
		return -ENOMEM;
	for (i = 0; i < usablemem_rgns.size; i++) {
		if (mem_regions_alloc_and_exclude(&system_memory_rgns,
					&crash_reserved_mem[i])) {
			fprintf(stderr, "Cannot allocate memory for ranges\n");
			return -ENOMEM;
		}
	}

	/*


@@ 190,7 182,7 @@ int load_crashdump_segments(struct kexec_info *info)
	if (err)
		return EFAILED;

	elf_info.page_offset = get_kernel_page_offset();
	get_page_offset((unsigned long *)&elf_info.page_offset);
	dbgprintf("%s: page_offset:   %016llx\n", __func__,
			elf_info.page_offset);



@@ 202,7 194,8 @@ int load_crashdump_segments(struct kexec_info *info)
		return EFAILED;

	elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 0,
		crash_reserved_mem.start, crash_reserved_mem.end,
		crash_reserved_mem[usablemem_rgns.size - 1].start,
		crash_reserved_mem[usablemem_rgns.size - 1].end,
		-1, 0);

	elfcorehdr_mem.start = elfcorehdr;


@@ 220,21 213,23 @@ int load_crashdump_segments(struct kexec_info *info)
 * virt_to_phys() in add_segment().
 * So let's fix up those values for later use so the memory base
 * (arm64_mm.phys_offset) will be correctly replaced with
 * crash_reserved_mem.start.
 * crash_reserved_mem[usablemem_rgns.size - 1].start.
 */
void fixup_elf_addrs(struct mem_ehdr *ehdr)
{
	struct mem_phdr *phdr;
	int i;

	ehdr->e_entry += - arm64_mem.phys_offset + crash_reserved_mem.start;
	ehdr->e_entry += -arm64_mem.phys_offset +
		crash_reserved_mem[usablemem_rgns.size - 1].start;

	for (i = 0; i < ehdr->e_phnum; i++) {
		phdr = &ehdr->e_phdr[i];
		if (phdr->p_type != PT_LOAD)
			continue;
		phdr->p_paddr +=
			(-arm64_mem.phys_offset + crash_reserved_mem.start);
			(-arm64_mem.phys_offset +
			 crash_reserved_mem[usablemem_rgns.size - 1].start);
	}
}



@@ 243,11 238,11 @@ int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
	if (!usablemem_rgns.size)
		kexec_iomem_for_each_line(NULL, iomem_range_callback, NULL);

	if (!crash_reserved_mem.end)
	if (!usablemem_rgns.size)
		return -1;

	*start = crash_reserved_mem.start;
	*end = crash_reserved_mem.end;
	*start = crash_reserved_mem[usablemem_rgns.size - 1].start;
	*end = crash_reserved_mem[usablemem_rgns.size - 1].end;

	return 0;
}

M kexec/arch/arm64/crashdump-arm64.h => kexec/arch/arm64/crashdump-arm64.h +5 -2
@@ 14,10 14,13 @@

#include "kexec.h"

#define CRASH_MAX_MEMORY_RANGES	32
#define CRASH_MAX_MEMORY_RANGES	32768

/* crash dump kernel support at most two regions, low_region and high region. */
#define CRASH_MAX_RESERVED_RANGES	2

extern struct memory_ranges usablemem_rgns;
extern struct memory_range crash_reserved_mem;
extern struct memory_range crash_reserved_mem[];
extern struct memory_range elfcorehdr_mem;

extern int load_crashdump_segments(struct kexec_info *info);

M kexec/arch/arm64/kexec-arm64.c => kexec/arch/arm64/kexec-arm64.c +176 -81
@@ 54,7 54,7 @@
static bool try_read_phys_offset_from_kcore = false;

/* Machine specific details. */
static int va_bits;
static int va_bits = -1;
static unsigned long page_offset;

/* Global varables the core kexec routines expect. */


@@ 456,22 456,32 @@ static void fill_property(void *buf, uint64_t val, uint32_t cells)
	}
}

static int fdt_setprop_range(void *fdt, int nodeoffset,
				const char *name, struct memory_range *range,
static int fdt_setprop_ranges(void *fdt, int nodeoffset, const char *name,
				struct memory_range *ranges, int nr_ranges, bool reverse,
				uint32_t address_cells, uint32_t size_cells)
{
	void *buf, *prop;
	size_t buf_size;
	int result;
	int i, result;
	struct memory_range *range;

	buf_size = (address_cells + size_cells) * sizeof(uint32_t);
	buf_size = (address_cells + size_cells) * sizeof(uint32_t) * nr_ranges;
	prop = buf = xmalloc(buf_size);
	if (!buf)
		return -ENOMEM;

	fill_property(prop, range->start, address_cells);
	prop += address_cells * sizeof(uint32_t);
	for (i = 0; i < nr_ranges; i++) {
		if (reverse)
			range = ranges + (nr_ranges - 1 - i);
		else
			range = ranges + i;

	fill_property(prop, range->end - range->start + 1, size_cells);
	prop += size_cells * sizeof(uint32_t);
		fill_property(prop, range->start, address_cells);
		prop += address_cells * sizeof(uint32_t);

		fill_property(prop, range->end - range->start + 1, size_cells);
		prop += size_cells * sizeof(uint32_t);
	}

	result = fdt_setprop(fdt, nodeoffset, name, buf, buf_size);



@@ 493,7 503,7 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
	int len, range_len;
	int nodeoffset;
	int new_size;
	int result, kaslr_seed;
	int i, result, kaslr_seed;

	result = fdt_check_header(dtb->buf);



@@ 524,18 534,20 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
		goto on_error;
	}

	if (!cells_size_fitted(address_cells, size_cells,
				&crash_reserved_mem)) {
		fprintf(stderr, "kexec: usable memory range doesn't fit cells-size.\n");
		result = -EINVAL;
		goto on_error;
	for (i = 0; i < usablemem_rgns.size; i++) {
		if (!cells_size_fitted(address_cells, size_cells,
					&crash_reserved_mem[i])) {
			fprintf(stderr, "kexec: usable memory range doesn't fit cells-size.\n");
			result = -EINVAL;
			goto on_error;
		}
	}

	/* duplicate dt blob */
	range_len = sizeof(uint32_t) * (address_cells + size_cells);
	new_size = fdt_totalsize(dtb->buf)
		+ fdt_prop_len(PROP_ELFCOREHDR, range_len)
		+ fdt_prop_len(PROP_USABLE_MEM_RANGE, range_len);
		+ fdt_prop_len(PROP_USABLE_MEM_RANGE, range_len * usablemem_rgns.size);

	new_buf = xmalloc(new_size);
	result = fdt_open_into(dtb->buf, new_buf, new_size);


@@ 619,8 631,8 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
	if (on_crash) {
		/* add linux,elfcorehdr */
		nodeoffset = fdt_path_offset(new_buf, "/chosen");
		result = fdt_setprop_range(new_buf, nodeoffset,
				PROP_ELFCOREHDR, &elfcorehdr_mem,
		result = fdt_setprop_ranges(new_buf, nodeoffset,
				PROP_ELFCOREHDR, &elfcorehdr_mem, 1, false,
				address_cells, size_cells);
		if (result) {
			dbgprintf("%s: fdt_setprop failed: %s\n", __func__,


@@ 629,10 641,17 @@ static int setup_2nd_dtb(struct dtb *dtb, char *command_line, int on_crash)
			goto on_error;
		}

		/* add linux,usable-memory-range */
		/*
		 * add linux,usable-memory-range
		 *
		 * crash dump kernel support one or two regions, to make
		 * compatibility with existing user-space and older kdump, the
		 * low region is always the last one.
		 */
		nodeoffset = fdt_path_offset(new_buf, "/chosen");
		result = fdt_setprop_range(new_buf, nodeoffset,
				PROP_USABLE_MEM_RANGE, &crash_reserved_mem,
		result = fdt_setprop_ranges(new_buf, nodeoffset,
				PROP_USABLE_MEM_RANGE,
				usablemem_rgns.ranges, usablemem_rgns.size, true,
				address_cells, size_cells);
		if (result) {
			dbgprintf("%s: fdt_setprop failed: %s\n", __func__,


@@ 665,13 684,13 @@ unsigned long arm64_locate_kernel_segment(struct kexec_info *info)
	if (info->kexec_flags & KEXEC_ON_CRASH) {
		unsigned long hole_end;

		hole = (crash_reserved_mem.start < mem_min ?
				mem_min : crash_reserved_mem.start);
		hole = (crash_reserved_mem[usablemem_rgns.size - 1].start < mem_min ?
				mem_min : crash_reserved_mem[usablemem_rgns.size - 1].start);
		hole = _ALIGN_UP(hole, MiB(2));
		hole_end = hole + arm64_mem.text_offset + arm64_mem.image_size;

		if ((hole_end > mem_max) ||
		    (hole_end > crash_reserved_mem.end)) {
		    (hole_end > crash_reserved_mem[usablemem_rgns.size - 1].end)) {
			dbgprintf("%s: Crash kernel out of range\n", __func__);
			hole = ULONG_MAX;
		}


@@ 745,7 764,7 @@ int arm64_load_other_segments(struct kexec_info *info,

	hole_min = image_base + arm64_mem.image_size;
	if (info->kexec_flags & KEXEC_ON_CRASH)
		hole_max = crash_reserved_mem.end;
		hole_max = crash_reserved_mem[usablemem_rgns.size - 1].end;
	else
		hole_max = ULONG_MAX;



@@ 859,7 878,7 @@ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz,
	add_segment_phys_virt(info, buf, bufsz, base, memsz, 1);
}

static inline void set_phys_offset(uint64_t v, char *set_method)
static inline void set_phys_offset(int64_t v, char *set_method)
{
	if (arm64_mem.phys_offset == arm64_mem_ngv
		|| v < arm64_mem.phys_offset) {


@@ 876,7 895,18 @@ static inline void set_phys_offset(uint64_t v, char *set_method)

static int get_va_bits(void)
{
	unsigned long long stext_sym_addr = get_kernel_sym("_stext");
	unsigned long long stext_sym_addr;

	/*
	 * if already got from kcore
	 */
	if (va_bits != -1)
		goto out;


	/* For kernel older than v4.19 */
	fprintf(stderr, "Warning, can't get the VA_BITS from kcore\n");
	stext_sym_addr = get_kernel_sym("_stext");

	if (stext_sym_addr == 0) {
		fprintf(stderr, "Can't get the symbol of _stext.\n");


@@ 900,6 930,7 @@ static int get_va_bits(void)
		return -1;
	}

out:
	dbgprintf("va_bits : %d\n", va_bits);

	return 0;


@@ 909,26 940,51 @@ static int get_va_bits(void)
 * get_page_offset - Helper for getting PAGE_OFFSET
 */

static int get_page_offset(void)
int get_page_offset(unsigned long *page_offset)
{
	unsigned long long text_sym_addr, kernel_va_mid;
	int ret;

	text_sym_addr = get_kernel_sym("_text");
	if (text_sym_addr == 0) {
		fprintf(stderr, "Can't get the symbol of _text to calculate page_offset.\n");
		return -1;
	}

	ret = get_va_bits();
	if (ret < 0)
		return ret;

	page_offset = (0xffffffffffffffffUL) << (va_bits - 1);
	dbgprintf("page_offset : %lx\n", page_offset);
	/* Since kernel 5.4, kernel image is put above
	 * UINT64_MAX << (va_bits - 1)
	 */
	kernel_va_mid = UINT64_MAX << (va_bits - 1);
	/* older kernel */
	if (text_sym_addr < kernel_va_mid)
		*page_offset = UINT64_MAX << (va_bits - 1);
	else
		*page_offset = UINT64_MAX << va_bits;

	dbgprintf("page_offset : %lx\n", *page_offset);

	return 0;
}

static void arm64_scan_vmcoreinfo(char *pos)
{
	const char *str;

	str = "NUMBER(VA_BITS)=";
	if (memcmp(str, pos, strlen(str)) == 0)
		va_bits = strtoul(pos + strlen(str), NULL, 10);
}

/**
 * get_phys_offset_from_vmcoreinfo_pt_note - Helper for getting PHYS_OFFSET
 * get_phys_offset_from_vmcoreinfo_pt_note - Helper for getting PHYS_OFFSET (and va_bits)
 * from VMCOREINFO note inside 'kcore'.
 */

static int get_phys_offset_from_vmcoreinfo_pt_note(unsigned long *phys_offset)
static int get_phys_offset_from_vmcoreinfo_pt_note(long *phys_offset)
{
	int fd, ret = 0;



@@ 937,6 993,7 @@ static int get_phys_offset_from_vmcoreinfo_pt_note(unsigned long *phys_offset)
		return EFAILED;
	}

	arch_scan_vmcoreinfo = arm64_scan_vmcoreinfo;
	ret = read_phys_offset_elf_kcore(fd, phys_offset);

	close(fd);


@@ 948,13 1005,13 @@ static int get_phys_offset_from_vmcoreinfo_pt_note(unsigned long *phys_offset)
 * from PT_LOADs inside 'kcore'.
 */

int get_phys_base_from_pt_load(unsigned long *phys_offset)
int get_phys_base_from_pt_load(long *phys_offset)
{
	int i, fd, ret;
	unsigned long long phys_start;
	unsigned long long virt_start;

	ret = get_page_offset();
	ret = get_page_offset(&page_offset);
	if (ret < 0)
		return ret;



@@ 979,12 1036,21 @@ int get_phys_base_from_pt_load(unsigned long *phys_offset)
	return 0;
}

static bool to_be_excluded(char *str)
static bool to_be_excluded(char *str, unsigned long long start, unsigned long long end)
{
	if (!strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL))) {
		uint64_t load_start, load_end;

		if (!get_crash_kernel_load_range(&load_start, &load_end) &&
		    (load_start == start) && (load_end == end))
			return false;

		return true;
	}

	if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) ||
	    !strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) ||
	    !strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) ||
	    !strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)))
	    !strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)))
		return false;
	else
		return true;


@@ 997,7 1063,7 @@ static bool to_be_excluded(char *str)
int get_memory_ranges(struct memory_range **range, int *ranges,
	unsigned long kexec_flags)
{
	unsigned long phys_offset = UINT64_MAX;
	long phys_offset = -1;
	FILE *fp;
	const char *iomem = proc_iomem();
	char line[MAX_LINE], *str;


@@ 1019,7 1085,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
		 */
		ret = get_phys_offset_from_vmcoreinfo_pt_note(&phys_offset);
		if (!ret) {
			if (phys_offset != UINT64_MAX)
			if (phys_offset != -1)
				set_phys_offset(phys_offset,
						"vmcoreinfo pt_note");
		} else {


@@ 1031,7 1097,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
			 */
			ret = get_phys_base_from_pt_load(&phys_offset);
			if (!ret)
				if (phys_offset != UINT64_MAX)
				if (phys_offset != -1)
					set_phys_offset(phys_offset,
							"pt_load");
		}


@@ 1066,7 1132,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
				memranges.size - 1,
				memranges.ranges[memranges.size - 1].start,
				memranges.ranges[memranges.size - 1].end);
		} else if (to_be_excluded(str)) {
		} else if (to_be_excluded(str, start, end)) {
			if (!memranges.size)
				continue;



@@ 1144,46 1210,34 @@ int machine_verify_elf_rel(struct mem_ehdr *ehdr)
	return (ehdr->e_machine == EM_AARCH64);
}

enum aarch64_rel_type {
	R_AARCH64_NONE = 0,
	R_AARCH64_ABS64 = 257,
	R_AARCH64_PREL32 = 261,
	R_AARCH64_MOVW_UABS_G0_NC = 264,
	R_AARCH64_MOVW_UABS_G1_NC = 266,
	R_AARCH64_MOVW_UABS_G2_NC = 268,
	R_AARCH64_MOVW_UABS_G3 =269,
	R_AARCH64_LD_PREL_LO19 = 273,
	R_AARCH64_ADR_PREL_LO21 = 274,
	R_AARCH64_ADR_PREL_PG_HI21 = 275,
	R_AARCH64_ADD_ABS_LO12_NC = 277,
	R_AARCH64_JUMP26 = 282,
	R_AARCH64_CALL26 = 283,
	R_AARCH64_LDST64_ABS_LO12_NC = 286,
	R_AARCH64_LDST128_ABS_LO12_NC = 299
};

static uint32_t get_bits(uint32_t value, int start, int end)
{
	uint32_t mask = ((uint32_t)1 << (end + 1 - start)) - 1;
	return (value >> start) & mask;
}

void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
	unsigned long r_type, void *ptr, unsigned long address,
	unsigned long value)
{
#if !defined(R_AARCH64_ABS64)
# define R_AARCH64_ABS64 257
#endif

#if !defined(R_AARCH64_PREL32)
# define R_AARCH64_PREL32 261
#endif

#if !defined(R_AARCH64_LD_PREL_LO19)
# define R_AARCH64_LD_PREL_LO19 273
#endif

#if !defined(R_AARCH64_ADR_PREL_LO21)
# define R_AARCH64_ADR_PREL_LO21 274
#endif

#if !defined(R_AARCH64_ADR_PREL_PG_HI21)
# define R_AARCH64_ADR_PREL_PG_HI21 275
#endif

#if !defined(R_AARCH64_ADD_ABS_LO12_NC)
# define R_AARCH64_ADD_ABS_LO12_NC 277
#endif

#if !defined(R_AARCH64_JUMP26)
# define R_AARCH64_JUMP26 282
#endif

#if !defined(R_AARCH64_CALL26)
# define R_AARCH64_CALL26 283
#endif

#if !defined(R_AARCH64_LDST64_ABS_LO12_NC)
# define R_AARCH64_LDST64_ABS_LO12_NC 286
#endif

	uint64_t *loc64;
	uint32_t *loc32;
	uint64_t *location = (uint64_t *)ptr;


@@ 1191,18 1245,47 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
	uint64_t imm;
	const char *type = NULL;

	switch(r_type) {
	switch((enum aarch64_rel_type)r_type) {
	case R_AARCH64_ABS64:
		type = "ABS64";
		loc64 = ptr;
		*loc64 = cpu_to_elf64(ehdr, elf64_to_cpu(ehdr, *loc64) + value);
		*loc64 = cpu_to_elf64(ehdr, value);
		break;
	case R_AARCH64_PREL32:
		type = "PREL32";
		loc32 = ptr;
		*loc32 = cpu_to_elf32(ehdr,
			elf32_to_cpu(ehdr, *loc32) + value - address);
		*loc32 = cpu_to_elf32(ehdr, value - address);
		break;

	/* Set a MOV[KZ] immediate field to bits [15:0] of X. No overflow check */
	case R_AARCH64_MOVW_UABS_G0_NC:
		type = "MOVW_UABS_G0_NC";
		loc32 = ptr;
		imm = get_bits(value, 0, 15);
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32) + (imm << 5));
		break;
	/* Set a MOV[KZ] immediate field to bits [31:16] of X. No overflow check */
	case R_AARCH64_MOVW_UABS_G1_NC:
		type = "MOVW_UABS_G1_NC";
		loc32 = ptr;
		imm = get_bits(value, 16, 31);
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32) + (imm << 5));
		break;
	/* Set a MOV[KZ] immediate field to bits [47:32] of X. No overflow check */
	case R_AARCH64_MOVW_UABS_G2_NC:
		type = "MOVW_UABS_G2_NC";
		loc32 = ptr;
		imm = get_bits(value, 32, 47);
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32) + (imm << 5));
		break;
	/* Set a MOV[KZ] immediate field to bits [63:48] of X */
	case R_AARCH64_MOVW_UABS_G3:
		type = "MOVW_UABS_G3";
		loc32 = ptr;
		imm = get_bits(value, 48, 63);
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32) + (imm << 5));
		break;

	case R_AARCH64_LD_PREL_LO19:
		type = "LD_PREL_LO19";
		loc32 = ptr;


@@ 1243,6 1326,7 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
			+ (((value - address) >> 2) & 0x3ffffff));
		break;
	/* encode imm field with bits [11:3] of value */
	case R_AARCH64_LDST64_ABS_LO12_NC:
		if (value & 7)
			die("%s: ERROR Unaligned value: %lx\n", __func__,


@@ 1252,6 1336,17 @@ void machine_apply_elf_rel(struct mem_ehdr *ehdr, struct mem_sym *UNUSED(sym),
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32)
			+ ((value & 0xff8) << (10 - 3)));
		break;

	/* encode imm field with bits [11:4] of value */
	case R_AARCH64_LDST128_ABS_LO12_NC:
		if (value & 15)
			die("%s: ERROR Unaligned value: %lx\n", __func__,
				value);
		type = "LDST128_ABS_LO12_NC";
		loc32 = ptr;
		imm = value & 0xff0;
		*loc32 = cpu_to_le32(le32_to_cpu(*loc32) + (imm << (10 - 4)));
		break;
	default:
		die("%s: ERROR Unknown type: %lu\n", __func__, r_type);
		break;

M kexec/arch/arm64/kexec-arm64.h => kexec/arch/arm64/kexec-arm64.h +2 -1
@@ 58,7 58,7 @@ extern off_t initrd_size;
 */

struct arm64_mem {
	uint64_t phys_offset;
	int64_t phys_offset;
	uint64_t text_offset;
	uint64_t image_size;
	uint64_t vp_offset;


@@ 69,6 69,7 @@ extern struct arm64_mem arm64_mem;

uint64_t get_phys_offset(void);
uint64_t get_vp_offset(void);
int get_page_offset(unsigned long *offset);

static inline void reset_vp_offset(void)
{

M kexec/arch/mips/crashdump-mips.c => kexec/arch/mips/crashdump-mips.c +4 -1
@@ 334,7 334,10 @@ static int patch_elf_info(void)
		if (strncmp(line, "cpu model", 9) == 0) {
			/* OCTEON uses a different page_offset. */
			if (strstr(line, "Octeon"))
				elf_info64.page_offset = 0x8000000000000000ULL;
				elf_info64.page_offset = OCTEON_PAGE_OFFSET;
			/* LOONGSON uses a different page_offset. */
			else if (strstr(line, "Loongson"))
				elf_info64.page_offset = LOONGSON_PAGE_OFFSET;
			break;
		}
	}

M kexec/arch/mips/crashdump-mips.h => kexec/arch/mips/crashdump-mips.h +2 -0
@@ 13,6 13,8 @@ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
#endif
#define __pa(x)		((unsigned long)(X) & 0x7fffffff)

#define LOONGSON_PAGE_OFFSET	0xffffffff80000000ULL
#define OCTEON_PAGE_OFFSET	0x8000000000000000ULL

#define CRASH_MAX_MEMMAP_NR	(KEXEC_MAX_SEGMENTS + 1)
#define CRASH_MAX_MEMORY_RANGES	(MAX_MEMORY_RANGES + 2)

M kexec/arch/mips/kexec-elf-mips.c => kexec/arch/mips/kexec-elf-mips.c +74 -2
@@ 40,6 40,77 @@ static const int probe_debug = 0;
#define CMDLINE_PREFIX "kexec "
static char cmdline_buf[COMMAND_LINE_SIZE] = CMDLINE_PREFIX;

/* Converts unsigned long to ascii string. */
static void ultoa(unsigned long i, char *str)
{
	int j = 0, k;
	char tmp;

	do {
		str[j++] = i % 10 + '0';
	} while ((i /= 10) > 0);
	str[j] = '\0';

	/* Reverse the string. */
	for (j = 0, k = strlen(str) - 1; j < k; j++, k--) {
		tmp = str[k];
		str[k] = str[j];
		str[j] = tmp;
	}
}

/* Adds initrd parameters to command line. */
static int cmdline_add_initrd(char *cmdline, unsigned long addr, char *new_para)
{
	int cmdlen, len;
	char str[30], *ptr;

	ptr = str;
	strcpy(str, new_para);
	ptr += strlen(str);
	ultoa(addr, ptr);
	len = strlen(str);
	cmdlen = strlen(cmdline) + len;
	if (cmdlen > (COMMAND_LINE_SIZE - 1))
		die("Command line overflow\n");
	strcat(cmdline, str);

	return 0;
}

/* add initrd to cmdline to compatible with previous platforms. */
static int patch_initrd_info(char *cmdline, unsigned long base,
			     unsigned long size)
{
	const char cpuinfo[] = "/proc/cpuinfo";
	char line[MAX_LINE];
	FILE *fp;
	unsigned long page_offset = PAGE_OFFSET;

	fp = fopen(cpuinfo, "r");
	if (!fp) {
		fprintf(stderr, "Cannot open %s: %s\n",
		cpuinfo, strerror(errno));
		return -1;
	}
	while (fgets(line, sizeof(line), fp) != 0) {
		if (strncmp(line, "cpu model", 9) == 0) {
			if (strstr(line, "Loongson")) {
				/* LOONGSON64  uses a different page_offset. */
				if (arch_options.core_header_type ==
				    CORE_TYPE_ELF64)
					page_offset = LOONGSON_PAGE_OFFSET;
				cmdline_add_initrd(cmdline,
					     page_offset + base, " rd_start=");
				cmdline_add_initrd(cmdline, size, " rd_size=");
				break;
			}
		}
	}
	fclose(fp);
	return 0;
}

int elf_mips_probe(const char *buf, off_t len)
{
	struct mem_ehdr ehdr;


@@ 171,9 242,10 @@ int elf_mips_load(int argc, char **argv, const char *buf, off_t len,
		/* Now that the buffer for initrd is prepared, update the dtb
		 * with an appropriate location */
		dtb_set_initrd(&dtb_buf, &dtb_length, initrd_base, initrd_base + initrd_size);
	}


		/* Add the initrd parameters to cmdline */
		patch_initrd_info(cmdline_buf, initrd_base, initrd_size);
	}
	/* This is a legacy method for commandline passing used
	 * currently by Octeon CPUs only */
	add_buffer(info, cmdline_buf, sizeof(cmdline_buf),

M kexec/arch/mips/kexec-mips.c => kexec/arch/mips/kexec-mips.c +13 -2
@@ 109,15 109,17 @@ int arch_process_options(int argc, char **argv)
	};
	static const char short_options[] = KEXEC_ARCH_OPT_STR;
	int opt;
	char *cmdline = NULL;
	const char *append = NULL;

	while ((opt = getopt_long(argc, argv, short_options,
				  options, 0)) != -1) {
		switch (opt) {
		case OPT_APPEND:
			arch_options.command_line = optarg;
			append = optarg;
			break;
		case OPT_REUSE_CMDLINE:
			arch_options.command_line = get_command_line();
			cmdline = get_command_line();
			break;
		case OPT_DTB:
			arch_options.dtb_file = optarg;


@@ 130,6 132,15 @@ int arch_process_options(int argc, char **argv)
		}
	}

	arch_options.command_line = concat_cmdline(cmdline, append);

	dbgprintf("%s:%d: command_line: %s\n", __func__, __LINE__,
		arch_options.command_line);
	dbgprintf("%s:%d: initrd: %s\n", __func__, __LINE__,
		arch_options.initrd_file);
	dbgprintf("%s:%d: dtb: %s\n", __func__, __LINE__,
		arch_options.dtb_file);

	return 0;
}


M kexec/arch/s390/crashdump-s390.c => kexec/arch/s390/crashdump-s390.c +2 -1
@@ 52,7 52,8 @@ static int create_elf_header(struct kexec_info *info, unsigned long crash_base,
	elfcorehdr_size = bufsz;
	snprintf(str, sizeof(str), " elfcorehdr=%ld@%ldK\n",
		 elfcorehdr_size, elfcorehdr / 1024);
	command_line_add(str);
	if (command_line_add(info, str))
		return -1;
#endif
	return 0;
}

M kexec/arch/s390/include/arch/options.h => kexec/arch/s390/include/arch/options.h +6 -4
@@ 1,9 1,10 @@
#ifndef KEXEC_ARCH_S390_OPTIONS_H
#define KEXEC_ARCH_S390_OPTIONS_H

#define OPT_ARCH_MAX	(OPT_MAX+0)
#define OPT_APPEND	OPT_MAX+0
#define OPT_RAMDISK	OPT_MAX+1
#define OPT_ARCH_MAX		(OPT_MAX+0)
#define OPT_APPEND		(OPT_MAX+0)
#define OPT_RAMDISK		(OPT_MAX+1)
#define OPT_REUSE_CMDLINE	(OPT_MAX+2)

/* Options relevant to the architecture (excluding loader-specific ones),
 * in this case none:


@@ 31,7 32,8 @@
	KEXEC_ARCH_OPTIONS				\
	{"command-line",     1, 0, OPT_APPEND},		\
	{"append",           1, 0, OPT_APPEND},		\
	{"initrd",	     1, 0, OPT_RAMDISK},
	{"initrd",	     1, 0, OPT_RAMDISK},	\
	{"reuse-cmdline",    0, 0, OPT_REUSE_CMDLINE },

#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR


M kexec/arch/s390/kexec-elf-rel-s390.c => kexec/arch/s390/kexec-elf-rel-s390.c +2 -1
@@ 56,6 56,7 @@ void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
	case R_390_PC16:	/* PC relative 16 bit.  */
	case R_390_PC16DBL:	/* PC relative 16 bit shifted by 1.  */
	case R_390_PC32DBL:	/* PC relative 32 bit shifted by 1.  */
	case R_390_PLT32DBL:	/* 32 bit PC rel. PLT shifted by 1.  */
	case R_390_PC32:	/* PC relative 32 bit.  */
	case R_390_PC64:	/* PC relative 64 bit.	*/
		val -= address;


@@ 63,7 64,7 @@ void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
			*(unsigned short *) loc = val;
		else if (r_type == R_390_PC16DBL)
			*(unsigned short *) loc = val >> 1;
		else if (r_type == R_390_PC32DBL)
		else if (r_type == R_390_PC32DBL || r_type == R_390_PLT32DBL)
			*(unsigned int *) loc = val >> 1;
		else if (r_type == R_390_PC32)
			*(unsigned int *) loc = val;

M kexec/arch/s390/kexec-image.c => kexec/arch/s390/kexec-image.c +53 -31
@@ 25,7 25,6 @@
#include <fcntl.h>

static uint64_t crash_base, crash_end;
static char command_line[COMMAND_LINESIZE];

static void add_segment_check(struct kexec_info *info, const void *buf,
			      size_t bufsz, unsigned long base, size_t memsz)


@@ 36,13 35,18 @@ static void add_segment_check(struct kexec_info *info, const void *buf,
	add_segment(info, buf, bufsz, crash_base + base, memsz);
}

int command_line_add(const char *str)
int command_line_add(struct kexec_info *info, const char *str)
{
	if (strlen(command_line) + strlen(str) + 1 > COMMAND_LINESIZE) {
		fprintf(stderr, "Command line too long.\n");
	char *tmp = NULL;

	tmp = concat_cmdline(info->command_line, str);
	if (!tmp) {
		fprintf(stderr, "out of memory\n");
		return -1;
	}
	strcat(command_line, str);

	free(info->command_line);
	info->command_line = tmp;
	return 0;
}



@@ 53,10 57,7 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)

	static const struct option options[] =
		{
			KEXEC_OPTIONS
			{"command-line",     1, 0, OPT_APPEND},
			{"append",           1, 0, OPT_APPEND},
			{"initrd",           1, 0, OPT_RAMDISK},
			KEXEC_ALL_OPTIONS
			{0,                  0, 0, 0},
		};
	static const char short_options[] = KEXEC_OPT_STR "";


@@ 64,12 65,16 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
		switch(opt) {
		case OPT_APPEND:
			if (command_line_add(optarg))
			if (command_line_add(info, optarg))
				return -1;
			break;
		case OPT_RAMDISK:
			ramdisk = optarg;
			break;
		case OPT_REUSE_CMDLINE:
			free(info->command_line);
			info->command_line = get_command_line();
			break;
		}
	}



@@ 78,13 83,16 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
		if (info->initrd_fd == -1) {
			fprintf(stderr, "Could not open initrd file %s:%s\n",
					ramdisk, strerror(errno));
			free(info->command_line);
			info->command_line = NULL;
			return -1;
		}
	}

	info->command_line = command_line;
	info->command_line_len = strlen (command_line) + 1;

	if (info->command_line)
		info->command_line_len = strlen(info->command_line) + 1;
	else
		info->command_line_len = 0;
	return 0;
}



@@ 97,22 105,18 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
	const char *ramdisk;
	off_t ramdisk_len;
	unsigned int ramdisk_origin;
	int opt;
	int opt, ret = -1;

	if (info->file_mode)
		return image_s390_load_file(argc, argv, info);

	static const struct option options[] =
		{
			KEXEC_OPTIONS
			{"command-line",     1, 0, OPT_APPEND},
			{"append",           1, 0, OPT_APPEND},
			{"initrd",           1, 0, OPT_RAMDISK},
			KEXEC_ALL_OPTIONS
			{0,                  0, 0, 0},
		};
	static const char short_options[] = KEXEC_OPT_STR "";

	command_line[0] = 0;
	ramdisk = NULL;
	ramdisk_len = 0;
	ramdisk_origin = 0;


@@ 120,9 124,13 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
	while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) {
		switch(opt) {
		case OPT_APPEND:
			if (command_line_add(optarg))
			if (command_line_add(info, optarg))
				return -1;
			break;
		case OPT_REUSE_CMDLINE:
			free(info->command_line);
			info->command_line = get_command_line();
			break;
		case OPT_RAMDISK:
			ramdisk = optarg;
			break;


@@ 132,7 140,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
	if (info->kexec_flags & KEXEC_ON_CRASH) {
		if (parse_iomem_single("Crash kernel\n", &crash_base,
				       &crash_end))
			return -1;
			goto out;
	}

	/* Add kernel segment */


@@ 151,7 159,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
		rd_buffer = slurp_file_mmap(ramdisk, &ramdisk_len);
		if (rd_buffer == NULL) {
			fprintf(stderr, "Could not read ramdisk.\n");
			return -1;
			goto out;
		}
		ramdisk_origin = MAX(RAMDISK_ORIGIN_ADDR, kernel_size);
		ramdisk_origin = _ALIGN_UP(ramdisk_origin, 0x100000);


@@ 160,7 168,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
	}
	if (info->kexec_flags & KEXEC_ON_CRASH) {
		if (load_crashdump_segments(info, crash_base, crash_end))
			return -1;
			goto out;
	} else {
		info->entry = (void *) IMAGE_READ_OFFSET;
	}


@@ 183,15 191,28 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
			*tmp = crash_end - crash_base + 1;
		}
	}
	/*
	 * We will write a probably given command line.
	 * First, erase the old area, then setup the new parameters:
	 */
	if (strlen(command_line) != 0) {
		memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE);
		memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line));

	if (info->command_line) {
		unsigned long maxsize;
		char *dest = krnl_buffer + COMMAND_LINE_OFFS;

		maxsize = *(unsigned long *)(krnl_buffer + MAX_COMMAND_LINESIZE_OFFS);
		if (!maxsize)
			maxsize = LEGACY_COMMAND_LINESIZE;

		if (strlen(info->command_line) > maxsize-1) {
			fprintf(stderr, "command line too long, maximum allowed size %ld\n",
				maxsize-1);
			goto out;
		}
		strncpy(dest, info->command_line, maxsize-1);
		dest[maxsize-1] = '\0';
	}
	return 0;
	ret = 0;
out:
	free(info->command_line);
	info->command_line = NULL;
	return ret;
}

int 


@@ 210,5 231,6 @@ image_s390_usage(void)
	printf("--command-line=STRING Set the kernel command line to STRING.\n"
	       "--append=STRING       Set the kernel command line to STRING.\n"
	       "--initrd=FILENAME     Use the file FILENAME as a ramdisk.\n"
	       "--reuse-cmdline       Use kernel command line from running system.\n"
		);
}

M kexec/arch/s390/kexec-s390.h => kexec/arch/s390/kexec-s390.h +11 -10
@@ 10,16 10,17 @@
#ifndef KEXEC_S390_H
#define KEXEC_S390_H

#define IMAGE_READ_OFFSET     0x10000
#define IMAGE_READ_OFFSET           0x10000

#define RAMDISK_ORIGIN_ADDR   0x800000
#define INITRD_START_OFFS     0x408
#define INITRD_SIZE_OFFS      0x410
#define OLDMEM_BASE_OFFS      0x418
#define OLDMEM_SIZE_OFFS      0x420
#define COMMAND_LINE_OFFS     0x480
#define COMMAND_LINESIZE      896
#define MAX_MEMORY_RANGES     1024
#define RAMDISK_ORIGIN_ADDR         0x800000
#define INITRD_START_OFFS           0x408
#define INITRD_SIZE_OFFS            0x410
#define OLDMEM_BASE_OFFS            0x418
#define OLDMEM_SIZE_OFFS            0x420
#define MAX_COMMAND_LINESIZE_OFFS   0x430
#define COMMAND_LINE_OFFS           0x480
#define LEGACY_COMMAND_LINESIZE     896
#define MAX_MEMORY_RANGES           1024

#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))


@@ 32,6 33,6 @@ extern int load_crashdump_segments(struct kexec_info *info,
				   unsigned long crash_end);
extern int get_memory_ranges_s390(struct memory_range range[], int *ranges,
				  int with_crashk);
extern int command_line_add(const char *str);
extern int command_line_add(struct kexec_info *info, const char *str);

#endif /* KEXEC_S390_H */

M kexec/kexec-elf-rel.c => kexec/kexec-elf-rel.c +7 -3
@@ 168,6 168,10 @@ int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
	return 0;
}

static unsigned long get_section_addralign(struct mem_shdr *shdr)
{
	return (shdr->sh_addralign == 0) ? 1 : shdr->sh_addralign;
}

int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
	unsigned long min, unsigned long max, int end)


@@ 219,7 223,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
		}
		if (shdr->sh_type != SHT_NOBITS) {
			unsigned long align;
			align = shdr->sh_addralign;
			align = get_section_addralign(shdr);
			/* See if I need more alignment */
			if (buf_align < align) {
				buf_align = align;


@@ 231,7 235,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
		}
		else {
			unsigned long align;
			align = shdr->sh_addralign;
			align = get_section_addralign(shdr);
			/* See if I need more alignment */
			if (bss_align < align) {
				bss_align = align;


@@ 265,7 269,7 @@ int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
		if (!(shdr->sh_flags & SHF_ALLOC)) {
			continue;
		}
		align = shdr->sh_addralign;
		align = get_section_addralign(shdr);
		if (shdr->sh_type != SHT_NOBITS) {
			unsigned long off;
			/* Adjust the address */

M kexec/kexec-xen.c => kexec/kexec-xen.c +8 -4
@@ 247,21 247,24 @@ int xen_kexec_status(uint64_t kexec_flags)
	return ret;
}

void xen_kexec_exec(uint64_t kexec_flags)
int xen_kexec_exec(uint64_t kexec_flags)
{
	xc_interface *xch;
	uint8_t type = KEXEC_TYPE_DEFAULT;
	int ret;

	xch = xc_interface_open(NULL, NULL, 0);
	if (!xch)
		return;
		return -1;

	if (kexec_flags & KEXEC_LIVE_UPDATE)
		type = KEXEC_TYPE_LIVE_UPDATE;

	xc_kexec_exec(xch, type);
	ret = xc_kexec_exec(xch, type);

	xc_interface_close(xch);

	return ret;
}

#else /* ! HAVE_LIBXENCTRL */


@@ 286,8 289,9 @@ int xen_kexec_status(uint64_t kexec_flags)
	return -1;
}

void xen_kexec_exec(uint64_t kexec_flags)
int xen_kexec_exec(uint64_t kexec_flags)
{
	return -1;
}

#endif

M kexec/kexec.c => kexec/kexec.c +81 -20
@@ 902,13 902,28 @@ static int my_shutdown(void)
}

/*
 *	Exec the new kernel (reboot)
 *	Exec the new kernel. If successful, this triggers an immediate reboot
 *	and does not return, but Xen Live Update is an exception (more on this
 *	below).
 */
static int my_exec(void)
{
	if (xen_present())
		xen_kexec_exec(kexec_flags);
	else
	if (xen_present()) {
		int ret;

		/*
		 * There are two cases in which the Xen hypercall may return:
		 * 1) An error occurred, e.g. the kexec image was not loaded.
		 *    The exact error is indicated by errno.
		 * 2) Live Update was successfully scheduled. Note that unlike
		 *    a normal kexec, Live Update happens asynchronously, i.e.
		 *    the hypercall merely schedules the kexec operation and
		 *    returns immediately.
		 */
		ret = xen_kexec_exec(kexec_flags);
		if ((kexec_flags & KEXEC_LIVE_UPDATE) && !ret)
			return 0;
	} else
		reboot(LINUX_REBOOT_CMD_KEXEC);
	/* I have failed if I make it here */
	fprintf(stderr, "kexec failed: %s\n", 


@@ 1106,6 1121,57 @@ static void remove_parameter(char *line, const char *param_name)
	}
}

static ssize_t _read(int fd, void *buf, size_t count)
{
	ssize_t ret, offset = 0;

	do {
		ret = read(fd, buf + offset, count - offset);
		if (ret < 0) {
			if ((errno == EINTR) ||	(errno == EAGAIN))
				continue;
			return ret;
		}
		offset += ret;
	} while (ret && offset < count);

	return offset;
}

static char *slurp_proc_file(const char *filename, size_t *len)
{
	ssize_t ret, startpos = 0;
	unsigned int size = 64;
	char *buf = NULL, *tmp;
	int fd;

	fd = open(filename, O_RDONLY);
	if (fd == -1)
		return NULL;

	do {
		size *= 2;
		tmp = realloc(buf, size);
		if (!tmp) {
			free(buf);
			return NULL;
		}
		buf = tmp;

		ret = _read(fd, buf + startpos, size - startpos);
		if (ret < 0) {
			free(buf);
			return NULL;
		}

		startpos += ret;

	} while(ret);

	*len = startpos;
	return buf;
}

/*
 * Returns the contents of the current command line to be used with
 * --reuse-cmdline option.  The function gets called from architecture specific


@@ 1121,25 1187,19 @@ static void remove_parameter(char *line, const char *param_name)
 */
char *get_command_line(void)
{
	FILE *fp;
	char *line;
	const int sizeof_line = 2048;

	line = malloc(sizeof_line);
	if (line == NULL)
		die("Could not allocate memory to read /proc/cmdline.");

	fp = fopen("/proc/cmdline", "r");
	if (!fp)
		die("Could not open /proc/cmdline.");

	if (fgets(line, sizeof_line, fp) == NULL)
		die("Can't read /proc/cmdline.");
	char *p, *line;
	size_t size;

	fclose(fp);
	line = slurp_proc_file("/proc/cmdline", &size);
	if (!line || !size)
		die("Failed to read /proc/cmdline\n");

	/* strip newline */
	line[strlen(line) - 1] = '\0';
	line[size-1] = '\0';

	p = strpbrk(line, "\r\n");
	if (p)
		*p = '\0';

	remove_parameter(line, "BOOT_IMAGE");
	if (kexec_flags & KEXEC_ON_CRASH)


@@ 1294,6 1354,7 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
		case EMSGSIZE:
			/* Reject by default. */
		default:
			fprintf(stderr, "kexec_file_load failed: %s\n", strerror(errno));
			ret = EFAILED;
			break;


M kexec/kexec.h => kexec/kexec.h +1 -1
@@ 324,7 324,7 @@ void cmdline_add_liveupdate(char **base);
int xen_present(void);
int xen_kexec_load(struct kexec_info *info);
int xen_kexec_unload(uint64_t kexec_flags);
void xen_kexec_exec(uint64_t kexec_flags);
int xen_kexec_exec(uint64_t kexec_flags);
int xen_kexec_status(uint64_t kexec_flags);

extern unsigned long long get_kernel_sym(const char *text);

M kexec/lzma.c => kexec/lzma.c +39 -0
@@ 155,6 155,42 @@ ssize_t lzread(LZFILE *lzfile, void *buf, size_t len)
	}
}

int is_lzma_file(const char *filename)
{
	FILE *fp;
	int ret = 0;
	uint8_t buf[13];

	if (!filename)
		return 0;

	fp = fopen(filename, "r");
	if (fp == NULL)
		return 0;

	const size_t size = fread(buf, 1, sizeof(buf), fp);

	if (size != 13) {
		/* file is too small to be a lzma file. */
		fclose(fp);
		return 0;
	}

	lzma_filter filter = { .id = LZMA_FILTER_LZMA1 };

	switch (lzma_properties_decode(&filter, NULL, buf, 5)) {
	case LZMA_OK:
		ret = 1;
		break;
	default:
		/* It's not a lzma file */
		ret = 0;
	}

	fclose(fp);
	return ret;
}

char *lzma_decompress_file(const char *filename, off_t *r_size)
{
	LZFILE *fp;


@@ 168,6 204,9 @@ char *lzma_decompress_file(const char *filename, off_t *r_size)
	if (!filename)
		return NULL;

	if (!is_lzma_file(filename))
		return NULL;

	fp = lzopen(filename, "rb");
	if (fp == 0) {
		dbgprintf("Cannot open `%s'\n", filename);

M purgatory/Makefile => purgatory/Makefile +1 -1
@@ 49,7 49,7 @@ $(PURGATORY): CFLAGS=$(PURGATORY_EXTRA_CFLAGS) \
		      $($(ARCH)_PURGATORY_EXTRA_CFLAGS) \
		      -Os -fno-builtin -ffreestanding \
		      -fno-zero-initialized-in-bss \
		      -fno-PIC -fno-PIE -fno-stack-protector
		      -fno-PIC -fno-PIE -fno-stack-protector -fno-tree-vectorize

$(PURGATORY): CPPFLAGS=$($(ARCH)_PURGATORY_EXTRA_CFLAGS) \
			-I$(srcdir)/purgatory/include \

M util_lib/elf_info.c => util_lib/elf_info.c +31 -4
@@ 310,6 310,8 @@ int get_pt_load(int idx,

#define NOT_FOUND_LONG_VALUE		(-1)

void (*arch_scan_vmcoreinfo)(char *pos);

void scan_vmcoreinfo(char *start, size_t size)
{
	char *last = start + size - 1;


@@ 551,6 553,9 @@ void scan_vmcoreinfo(char *start, size_t size)
			}
		}

		if (arch_scan_vmcoreinfo != NULL)
			(*arch_scan_vmcoreinfo)(pos);

		if (last_line)
			break;
	}


@@ 758,8 763,9 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
{
#define OUT_BUF_SIZE	4096
	uint64_t log_buf, log_buf_offset, ts_nsec;
	uint32_t log_first_idx, log_next_idx, current_idx, len = 0, i;
	uint32_t log_buf_len, log_first_idx, log_next_idx, current_idx, len = 0, i;
	char *buf, out_buf[OUT_BUF_SIZE];
	bool has_wrapped_around = false;
	ssize_t ret;
	char *msg;
	uint16_t text_len;


@@ 806,6 812,7 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
	}

	log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr));
	log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr));

	log_first_idx = read_file_u32(fd, vaddr_to_offset(log_first_idx_vaddr));
	log_next_idx = read_file_u32(fd, vaddr_to_offset(log_next_idx_vaddr));


@@ 877,11 884,31 @@ static void dump_dmesg_structured(int fd, void (*handler)(char*, unsigned int))
		 * and read the message at the start of the buffer.
		 */
		loglen = struct_val_u16(buf, log_offset_len);
		if (!loglen)
		if (!loglen) {
			if (has_wrapped_around) {
				if (len && handler)
					handler(out_buf, len);
				fprintf(stderr, "Cycle when parsing dmesg detected.\n");
				fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
				fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
					log_buf, current_idx);
				exit(68);
			}
			current_idx = 0;
		else
			has_wrapped_around = true;
		} else {
			/* Move to next record */
			current_idx += loglen;
			if(current_idx > log_buf_len - log_sz) {
				if (len && handler)
					handler(out_buf, len);
				fprintf(stderr, "Index outside log_buf detected.\n");
				fprintf(stderr, "The prink log_buf is most likely corrupted.\n");
				fprintf(stderr, "log_buf = 0x%lx, idx = 0x%x\n",
					log_buf, current_idx);
				exit(69);
			}
		}
	}
	free(buf);
	if (len && handler)


@@ 1236,7 1263,7 @@ int read_elf(int fd)
	return 0;
}

int read_phys_offset_elf_kcore(int fd, unsigned long *phys_off)
int read_phys_offset_elf_kcore(int fd, long *phys_off)
{
	int ret;


M util_lib/include/elf_info.h => util_lib/include/elf_info.h +2 -1
@@ 28,8 28,9 @@ int get_pt_load(int idx,
	unsigned long long *phys_end,
	unsigned long long *virt_start,
	unsigned long long *virt_end);
int read_phys_offset_elf_kcore(int fd, unsigned long *phys_off);
int read_phys_offset_elf_kcore(int fd, long *phys_off);
int read_elf(int fd);
void dump_dmesg(int fd, void (*handler)(char*, unsigned int));
extern void (*arch_scan_vmcoreinfo)(char *pos);

#endif /* ELF_INFO_H */