検索条件
全1件
(1/1ページ)
SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, struct kexec_segment __user *, segments, unsigned long, flags) { ... result = kimage_normal_alloc(&image, entry, nr_segments, segments); ... result = machine_kexec_prepare(image); ... for (i = 0; i < nr_segments; i++) { result = kimage_load_segment(image, &image->segment[i]); ... kimage_terminate(image);kernel imageやinitrdのイメージを物理ページへ転送して起動準備。
static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments) { ... image->control_code_page = kimage_alloc_control_pages(image, get_order(KEXEC_CONTROL_PAGE_SIZE));image->control_code_page には、連続した4096page=16MBの物理連続空間が割り当てられる。
struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order) { struct page *pages = NULL; switch (image->type) { case KEXEC_TYPE_DEFAULT: pages = kimage_alloc_normal_control_pages(image, order); break;DEFAULTとCRASH時の2種類あり。今はDEFAULTを追う。
static struct page *kimage_alloc_normal_control_pages(struct kimage *image, unsigned int order) { pages = kimage_alloc_pages(GFP_KERNEL, order); ... if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || kimage_is_destination_range(image, addr, eaddr)) { list_add(&pages->lru, &extra_pages); pages = NULL; } } while (!pages); ... kimage_free_page_list(&extra_pages);物理的に連続するページを確保して、転送先アドレスとの重複チェックを行う。
int machine_kexec_prepare(struct kimage *image) ... memblock_is_region_memory(current_segment->mem,current_segment->memsz)現在のkernelが把握している memory空間の有効範囲が指示されているかをチェックしているようだ。
static int kimage_load_segment(struct kimage *image, struct kexec_segment *segment) { ... case KEXEC_TYPE_DEFAULT: result = kimage_load_normal_segment(image, segment);
static int kimage_load_normal_segment(struct kimage *image, struct kexec_segment *segment) {
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) { #ifdef CONFIG_KEXEC case LINUX_REBOOT_CMD_KEXEC: ret = kernel_kexec();kexecシステムコールで保持したイメージデータは、
/* * Move into place and start executing a preloaded standalone * executable. If nothing was preloaded return an error. */ int kernel_kexec(void) { { kexec_in_progress = true; kernel_restart_prepare(NULL); migrate_to_reboot_cpu(); printk(KERN_EMERG "Starting new kernel\n"); machine_shutdown(); } machine_kexec(kexec_image);ドライバ・ユーザヘルパ?の終了をしつつ(kernel_restart_prepare(NULL))、
void kernel_restart_prepare(char *cmd) { blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; usermodehelper_disable(); device_shutdown(); }
void machine_kexec(struct kimage *image) { ... unsigned long reboot_entry = (unsigned long)relocate_new_kernel; ... /* copy our kernel relocation code to the control code page */ reboot_entry = fncpy(reboot_code_buffer, reboot_entry, relocate_new_kernel_size); ★imageで渡されたロードイメージをページ単位で保存し、 そのPFNをLookUpTableとして管理している。 そのポインタを受け取って、指定された物理アドレスへイメージを 転送するアセンブラコード本体を、コレでコピーする。 コードはentry pointへのjumpも含まれている。 ... printk(KERN_INFO "Bye!\n"); if (kexec_reinit) kexec_reinit(); soft_restart(reboot_entry_phys); }
ENTRY(relocate_new_kernel) ... /* Jump to relocated kernel */ mov lr,r1 mov r0,#0 ldr r1,kexec_mach_type ldr r2,kexec_boot_atags ARM( mov pc, lr ) THUMB( bx lr ) .align .globl kexec_start_address kexec_start_address: .long 0x0 .globl kexec_indirection_page kexec_indirection_page: .long 0x0 .globl kexec_mach_type kexec_mach_type: .long 0x0 /* phy addr of the atags for the new kernel */ .globl kexec_boot_atags kexec_boot_atags: .long 0x0 ENDPROC(relocate_new_kernel)
void soft_restart(unsigned long addr) { u64 *stack = soft_restart_stack + ARRAY_SIZE(soft_restart_stack); /* Disable interrupts first */ ... /* Disable the L2 if we're the last man standing. */ ... /* Change to the new stack and continue with the reset. */ call_with_stack(__soft_restart, (void *)addr, (void *)stack);FILE: arch/arm//lib/call_with_stack.S
ENTRY(call_with_stack) str sp, [r2, #-4]! str lr, [r2, #-4]! mov sp, r2 mov r2, r0 mov r0, r1 adr lr, BSYM(1f) mov pc, r2 1: ldr lr, [sp] ldr sp, [sp, #4] mov pc, lr ENDPROC(call_with_stack)ARM-EABI仕様にしたがい、r0にLUTへのポインタ(PFN/dest-adr/end-mark/next-LUTの入った先頭ページ)、r1に関数アドレス、r2にスタック(static変数)が渡されてくる。
void (*kexec_reinit)(void);