int image_arm64_load(int argc, char **argv, const char *kernel_buf, off_t kernel_size, struct kexec_info *info) { int result; uint64_t start; const struct arm64_image_header *h; char *header_option = NULL; h = (const struct arm64_image_header *)(kernel_buf); arm64_mem.text_offset = le64_to_cpu(h->text_offset); arm64_mem.image_size = le64_to_cpu(h->image_size); arm64_mem.page_offset = get_kernel_page_offset(); if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, &header_option); if (result) { fprintf(stderr, "kexec: load crashdump segments failed.\n"); return -1; } start = crash_reserved_mem.start; } else { result = parse_iomem_single("Kernel code\n", &start, NULL); if (result) { fprintf(stderr, "kexec: Could not get kernel code address.\n"); return -1; } start -= arm64_mem.text_offset; } /* Add kernel */ add_segment_phys_virt(info, kernel_buf, kernel_size, start + arm64_mem.text_offset, kernel_size, 0); info->entry = (void *)start + arm64_mem.text_offset; result = arm64_load_other_segments(info, (unsigned long)info->entry, header_option); if (header_option) free(header_option); return result; }
unsigned long add_buffer_phys_virt(struct kexec_info *info, const void *buf, unsigned long bufsz, unsigned long memsz, unsigned long buf_align, unsigned long buf_min, unsigned long buf_max, int buf_end, int phys) { unsigned long base, start, end; int result; int pagesize; result = sort_segments(info); if (result < 0) { die("sort_segments failed\n"); } /* Round memsz up to a multiple of pagesize */ pagesize = getpagesize(); memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1); // base = locate_hole(info, memsz, buf_align, buf_min, buf_max, buf_end); /* local_hole will find memory at end of RAM where capture kernel * is generally allocated, but in case HIGHMEM is supported then * capture kernel need not be at the end of RAM */ result = get_crashkernel_mem_range(&start, &end); if (result < 0) { die("get_crashkernel_mem_range failed"); } base = end - memsz + 1; if ((base <= start) || (base >= end)) { die("locate_hole failed\n"); } add_segment_phys_virt(info, buf, bufsz, base, memsz, phys); return base; }
/* * add_segment() should convert base to a physical address on superh, * while the default is just to work with base as is */ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); }