/** * machine_kexec_prepare - Prepare for a kexec reboot. * * Called from the core kexec code when a kernel image is loaded. */ int machine_kexec_prepare(struct kimage *image) { kexec_image_info(image); fill_bypass(image); if (bypass_purgatory) { arm64_kexec_kimage_start = bypass.kernel; arm64_kexec_dtb_addr = bypass.dtb; } else { arm64_kexec_kimage_start = image->start; arm64_kexec_dtb_addr = 0; } return 0; }
/** * machine_kexec_prepare - Prepare for a kexec reboot. * * Called from the core kexec code when a kernel image is loaded. */ int machine_kexec_prepare(struct kimage *image) { struct kexec_segment *current_segment; __be32 header; int i, err; /* * No segment at default ATAGs address. try to locate * a dtb using magic. */ for (i = 0; i < image->nr_segments; i++) { current_segment = &image->segment[i]; if (!memblock_is_region_memory(current_segment->mem, current_segment->memsz)) return -EINVAL; #ifdef CONFIG_KEXEC_HARDBOOT if(current_segment->mem == image->start) kexec_kernel_len = current_segment->memsz; #endif err = get_user(header, (__be32*)current_segment->buf); if (err) return err; if (be32_to_cpu(header) == OF_DT_HEADER) { kexec_boot_atags = current_segment->mem; #ifdef CONFIG_KEXEC_HARDBOOT kexec_boot_atags_len = current_segment->memsz; #endif } } arm64_kexec_kimage_start = image->start; kexec_image_info(image); return 0; }
/** * machine_kexec - Do the kexec reboot. * * Called from the core kexec code for a sys_reboot with LINUX_REBOOT_CMD_KEXEC. */ void machine_kexec(struct kimage *image) { phys_addr_t reboot_code_buffer_phys; void *reboot_code_buffer; BUG_ON(num_online_cpus() > 1); arm64_kexec_kimage_head = image->head; reboot_code_buffer_phys = page_to_phys(image->control_code_page); reboot_code_buffer = phys_to_virt(reboot_code_buffer_phys); kexec_image_info(image); pr_devel("%s:%d: control_code_page: %p\n", __func__, __LINE__, image->control_code_page); pr_devel("%s:%d: reboot_code_buffer_phys: %pa\n", __func__, __LINE__, &reboot_code_buffer_phys); pr_devel("%s:%d: reboot_code_buffer: %p\n", __func__, __LINE__, reboot_code_buffer); pr_devel("%s:%d: relocate_new_kernel: %p\n", __func__, __LINE__, relocate_new_kernel); pr_devel("%s:%d: relocate_new_kernel_size: 0x%lx(%lu) bytes\n", __func__, __LINE__, relocate_new_kernel_size, relocate_new_kernel_size); pr_devel("%s:%d: kexec_dtb_addr: %lx\n", __func__, __LINE__, arm64_kexec_dtb_addr); pr_devel("%s:%d: kexec_kimage_head: %lx\n", __func__, __LINE__, arm64_kexec_kimage_head); pr_devel("%s:%d: kexec_kimage_start: %lx\n", __func__, __LINE__, arm64_kexec_kimage_start); #ifdef CONFIG_KEXEC_HARDBOOT if (!kexec_boot_atags) kexec_boot_atags = image->start - 0x8000 + 0x1000; kexec_hardboot = image->hardboot; #endif /* * Copy relocate_new_kernel to the reboot_code_buffer for use * after the kernel is shut down. */ memcpy(reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size); /* Flush the reboot_code_buffer in preparation for its execution. */ __flush_dcache_area(reboot_code_buffer, relocate_new_kernel_size); /* Flush the kimage list. */ kexec_list_flush(image->head); pr_info("Bye!\n"); /* Disable all DAIF exceptions. */ asm volatile ("msr daifset, #0xf" : : : "memory"); /* * soft_restart() will shutdown the MMU, disable data caches, then * transfer control to the reboot_code_buffer which contains a copy of * the relocate_new_kernel routine. relocate_new_kernel will use * physical addressing to relocate the new kernel to its final position * and then will transfer control to the entry point of the new kernel. */ soft_restart(reboot_code_buffer_phys); }