検索条件
全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.SENTRY(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);