[Xen-devel] [PATCH 4/9] kexec: extend hypercall with improved load/unload ops
Don Slutz
dslutz at verizon.com
Thu Nov 7 15:56:35 EST 2013
For what it is worth.
Reviewed-by: Don Slutz <dslutz at verizon.com>
-Don Slutz
On 11/06/13 09:49, David Vrabel wrote:
> From: David Vrabel <david.vrabel at citrix.com>
>
> In the existing kexec hypercall, the load and unload ops depend on
> internals of the Linux kernel (the page list and code page provided by
> the kernel). The code page is used to transition between Xen context
> and the image so using kernel code doesn't make sense and will not
> work for PVH guests.
>
> Add replacement KEXEC_CMD_kexec_load and KEXEC_CMD_kexec_unload ops
> that no longer require a code page to be provided by the guest -- Xen
> now provides the code for calling the image directly.
>
> The new load op looks similar to the Linux kexec_load system call and
> allows the guest to provide the image data to be loaded. The guest
> specifies the architecture of the image which may be a 32-bit subarch
> of the hypervisor's architecture (i.e., an EM_386 image on an
> EM_X86_64 hypervisor).
>
> The toolstack can now load images without kernel involvement. This is
> required for supporting kexec when using a dom0 with an upstream
> kernel.
>
> Crash images are copied directly into the crash region on load.
> Default images are copied into domheap pages and a list of source and
> destination machine addresses is created. This is list is used in
> kexec_reloc() to relocate the image to its destination.
>
> The old load and unload sub-ops are still available (as
> KEXEC_CMD_load_v1 and KEXEC_CMD_unload_v1) and are implemented on top
> of the new infrastructure.
>
> Signed-off-by: David Vrabel <david.vrabel at citrix.com>
> Reviewed-by: Andrew Cooper <andrew.cooper3 at citrix.com>
> ---
> xen/arch/x86/machine_kexec.c | 192 +++++++++++------
> xen/arch/x86/x86_64/Makefile | 2 +-
> xen/arch/x86/x86_64/compat_kexec.S | 187 ----------------
> xen/arch/x86/x86_64/kexec_reloc.S | 198 +++++++++++++++++
> xen/common/kexec.c | 398 +++++++++++++++++++++++++++++------
> xen/common/kimage.c | 122 +++++++++++-
> xen/include/asm-x86/fixmap.h | 3 -
> xen/include/asm-x86/machine_kexec.h | 16 ++
> xen/include/xen/kexec.h | 16 +-
> xen/include/xen/kimage.h | 6 +
> 10 files changed, 804 insertions(+), 336 deletions(-)
> delete mode 100644 xen/arch/x86/x86_64/compat_kexec.S
> create mode 100644 xen/arch/x86/x86_64/kexec_reloc.S
> create mode 100644 xen/include/asm-x86/machine_kexec.h
>
> diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c
> index 68b9705..b70d5a6 100644
> --- a/xen/arch/x86/machine_kexec.c
> +++ b/xen/arch/x86/machine_kexec.c
> @@ -1,9 +1,18 @@
> /******************************************************************************
> * machine_kexec.c
> *
> + * Copyright (C) 2013 Citrix Systems R&D Ltd.
> + *
> + * Portions derived from Linux's arch/x86/kernel/machine_kexec_64.c.
> + *
> + * Copyright (C) 2002-2005 Eric Biederman <ebiederm at xmission.com>
> + *
> * Xen port written by:
> * - Simon 'Horms' Horman <horms at verge.net.au>
> * - Magnus Damm <magnus at valinux.co.jp>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2. See the file COPYING for more details.
> */
>
> #include <xen/types.h>
> @@ -11,63 +20,124 @@
> #include <xen/guest_access.h>
> #include <asm/fixmap.h>
> #include <asm/hpet.h>
> +#include <asm/page.h>
> +#include <asm/machine_kexec.h>
>
> -typedef void (*relocate_new_kernel_t)(
> - unsigned long indirection_page,
> - unsigned long *page_list,
> - unsigned long start_address,
> - unsigned int preserve_context);
> -
> -int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
> +/*
> + * Add a mapping for a page to the page tables used during kexec.
> + */
> +int machine_kexec_add_page(struct kexec_image *image, unsigned long vaddr,
> + unsigned long maddr)
> {
> - unsigned long prev_ma = 0;
> - int fix_base = FIX_KEXEC_BASE_0 + (slot * (KEXEC_XEN_NO_PAGES >> 1));
> - int k;
> + struct page_info *l4_page;
> + struct page_info *l3_page;
> + struct page_info *l2_page;
> + struct page_info *l1_page;
> + l4_pgentry_t *l4 = NULL;
> + l3_pgentry_t *l3 = NULL;
> + l2_pgentry_t *l2 = NULL;
> + l1_pgentry_t *l1 = NULL;
> + int ret = -ENOMEM;
> +
> + l4_page = image->aux_page;
> + if ( !l4_page )
> + {
> + l4_page = kimage_alloc_control_page(image, 0);
> + if ( !l4_page )
> + goto out;
> + image->aux_page = l4_page;
> + }
>
> - /* setup fixmap to point to our pages and record the virtual address
> - * in every odd index in page_list[].
> - */
> + l4 = __map_domain_page(l4_page);
> + l4 += l4_table_offset(vaddr);
> + if ( !(l4e_get_flags(*l4) & _PAGE_PRESENT) )
> + {
> + l3_page = kimage_alloc_control_page(image, 0);
> + if ( !l3_page )
> + goto out;
> + l4e_write(l4, l4e_from_page(l3_page, __PAGE_HYPERVISOR));
> + }
> + else
> + l3_page = l4e_get_page(*l4);
> +
> + l3 = __map_domain_page(l3_page);
> + l3 += l3_table_offset(vaddr);
> + if ( !(l3e_get_flags(*l3) & _PAGE_PRESENT) )
> + {
> + l2_page = kimage_alloc_control_page(image, 0);
> + if ( !l2_page )
> + goto out;
> + l3e_write(l3, l3e_from_page(l2_page, __PAGE_HYPERVISOR));
> + }
> + else
> + l2_page = l3e_get_page(*l3);
> +
> + l2 = __map_domain_page(l2_page);
> + l2 += l2_table_offset(vaddr);
> + if ( !(l2e_get_flags(*l2) & _PAGE_PRESENT) )
> + {
> + l1_page = kimage_alloc_control_page(image, 0);
> + if ( !l1_page )
> + goto out;
> + l2e_write(l2, l2e_from_page(l1_page, __PAGE_HYPERVISOR));
> + }
> + else
> + l1_page = l2e_get_page(*l2);
> +
> + l1 = __map_domain_page(l1_page);
> + l1 += l1_table_offset(vaddr);
> + l1e_write(l1, l1e_from_pfn(maddr >> PAGE_SHIFT, __PAGE_HYPERVISOR));
> +
> + ret = 0;
> +out:
> + if ( l1 )
> + unmap_domain_page(l1);
> + if ( l2 )
> + unmap_domain_page(l2);
> + if ( l3 )
> + unmap_domain_page(l3);
> + if ( l4 )
> + unmap_domain_page(l4);
> + return ret;
> +}
>
> - for ( k = 0; k < KEXEC_XEN_NO_PAGES; k++ )
> +int machine_kexec_load(struct kexec_image *image)
> +{
> + void *code_page;
> + int ret;
> +
> + switch ( image->arch )
> {
> - if ( (k & 1) == 0 )
> - {
> - /* Even pages: machine address. */
> - prev_ma = image->page_list[k];
> - }
> - else
> - {
> - /* Odd pages: va for previous ma. */
> - if ( is_pv_32on64_domain(dom0) )
> - {
> - /*
> - * The compatability bounce code sets up a page table
> - * with a 1-1 mapping of the first 1G of memory so
> - * VA==PA here.
> - *
> - * This Linux purgatory code still sets up separate
> - * high and low mappings on the control page (entries
> - * 0 and 1) but it is harmless if they are equal since
> - * that PT is not live at the time.
> - */
> - image->page_list[k] = prev_ma;
> - }
> - else
> - {
> - set_fixmap(fix_base + (k >> 1), prev_ma);
> - image->page_list[k] = fix_to_virt(fix_base + (k >> 1));
> - }
> - }
> + case EM_386:
> + case EM_X86_64:
> + break;
> + default:
> + return -EINVAL;
> }
>
> + code_page = __map_domain_page(image->control_code_page);
> + memcpy(code_page, kexec_reloc, kexec_reloc_size);
> + unmap_domain_page(code_page);
> +
> + /*
> + * Add a mapping for the control code page to the same virtual
> + * address as kexec_reloc. This allows us to keep running after
> + * these page tables are loaded in kexec_reloc.
> + */
> + ret = machine_kexec_add_page(image, (unsigned long)kexec_reloc,
> + page_to_maddr(image->control_code_page));
> + if ( ret < 0 )
> + return ret;
> +
> return 0;
> }
>
> -void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image)
> +void machine_kexec_unload(struct kexec_image *image)
> {
> + /* no-op. kimage_free() frees all control pages. */
> }
>
> -void machine_reboot_kexec(xen_kexec_image_t *image)
> +void machine_reboot_kexec(struct kexec_image *image)
> {
> BUG_ON(smp_processor_id() != 0);
> smp_send_stop();
> @@ -75,13 +145,10 @@ void machine_reboot_kexec(xen_kexec_image_t *image)
> BUG();
> }
>
> -void machine_kexec(xen_kexec_image_t *image)
> +void machine_kexec(struct kexec_image *image)
> {
> - struct desc_ptr gdt_desc = {
> - .base = (unsigned long)(boot_cpu_gdt_table - FIRST_RESERVED_GDT_ENTRY),
> - .limit = LAST_RESERVED_GDT_BYTE
> - };
> int i;
> + unsigned long reloc_flags = 0;
>
> /* We are about to permenantly jump out of the Xen context into the kexec
> * purgatory code. We really dont want to be still servicing interupts.
> @@ -109,29 +176,12 @@ void machine_kexec(xen_kexec_image_t *image)
> * not like running with NMIs disabled. */
> enable_nmis();
>
> - /*
> - * compat_machine_kexec() returns to idle pagetables, which requires us
> - * to be running on a static GDT mapping (idle pagetables have no GDT
> - * mappings in their per-domain mapping area).
> - */
> - asm volatile ( "lgdt %0" : : "m" (gdt_desc) );
> + if ( image->arch == EM_386 )
> + reloc_flags |= KEXEC_RELOC_FLAG_COMPAT;
>
> - if ( is_pv_32on64_domain(dom0) )
> - {
> - compat_machine_kexec(image->page_list[1],
> - image->indirection_page,
> - image->page_list,
> - image->start_address);
> - }
> - else
> - {
> - relocate_new_kernel_t rnk;
> -
> - rnk = (relocate_new_kernel_t) image->page_list[1];
> - (*rnk)(image->indirection_page, image->page_list,
> - image->start_address,
> - 0 /* preserve_context */);
> - }
> + kexec_reloc(page_to_maddr(image->control_code_page),
> + page_to_maddr(image->aux_page),
> + image->head, image->entry_maddr, reloc_flags);
> }
>
> int machine_kexec_get(xen_kexec_range_t *range)
> diff --git a/xen/arch/x86/x86_64/Makefile b/xen/arch/x86/x86_64/Makefile
> index d56e12d..7f8fb3d 100644
> --- a/xen/arch/x86/x86_64/Makefile
> +++ b/xen/arch/x86/x86_64/Makefile
> @@ -11,11 +11,11 @@ obj-y += mmconf-fam10h.o
> obj-y += mmconfig_64.o
> obj-y += mmconfig-shared.o
> obj-y += compat.o
> -obj-bin-y += compat_kexec.o
> obj-y += domain.o
> obj-y += physdev.o
> obj-y += platform_hypercall.o
> obj-y += cpu_idle.o
> obj-y += cpufreq.o
> +obj-bin-y += kexec_reloc.o
>
> obj-$(crash_debug) += gdbstub.o
> diff --git a/xen/arch/x86/x86_64/compat_kexec.S b/xen/arch/x86/x86_64/compat_kexec.S
> deleted file mode 100644
> index fc92af9..0000000
> --- a/xen/arch/x86/x86_64/compat_kexec.S
> +++ /dev/null
> @@ -1,187 +0,0 @@
> -/*
> - * Compatibility kexec handler.
> - */
> -
> -/*
> - * NOTE: We rely on Xen not relocating itself above the 4G boundary. This is
> - * currently true but if it ever changes then compat_pg_table will
> - * need to be moved back below 4G at run time.
> - */
> -
> -#include <xen/config.h>
> -
> -#include <asm/asm_defns.h>
> -#include <asm/msr.h>
> -#include <asm/page.h>
> -
> -/* The unrelocated physical address of a symbol. */
> -#define SYM_PHYS(sym) ((sym) - __XEN_VIRT_START)
> -
> -/* Load physical address of symbol into register and relocate it. */
> -#define RELOCATE_SYM(sym,reg) mov $SYM_PHYS(sym), reg ; \
> - add xen_phys_start(%rip), reg
> -
> -/*
> - * Relocate a physical address in memory. Size of temporary register
> - * determines size of the value to relocate.
> - */
> -#define RELOCATE_MEM(addr,reg) mov addr(%rip), reg ; \
> - add xen_phys_start(%rip), reg ; \
> - mov reg, addr(%rip)
> -
> - .text
> -
> - .code64
> -
> -ENTRY(compat_machine_kexec)
> - /* x86/64 x86/32 */
> - /* %rdi - relocate_new_kernel_t CALL */
> - /* %rsi - indirection page 4(%esp) */
> - /* %rdx - page_list 8(%esp) */
> - /* %rcx - start address 12(%esp) */
> - /* cpu has pae 16(%esp) */
> -
> - /* Shim the 64 bit page_list into a 32 bit page_list. */
> - mov $12,%r9
> - lea compat_page_list(%rip), %rbx
> -1: dec %r9
> - movl (%rdx,%r9,8),%eax
> - movl %eax,(%rbx,%r9,4)
> - test %r9,%r9
> - jnz 1b
> -
> - RELOCATE_SYM(compat_page_list,%rdx)
> -
> - /* Relocate compatibility mode entry point address. */
> - RELOCATE_MEM(compatibility_mode_far,%eax)
> -
> - /* Relocate compat_pg_table. */
> - RELOCATE_MEM(compat_pg_table, %rax)
> - RELOCATE_MEM(compat_pg_table+0x8, %rax)
> - RELOCATE_MEM(compat_pg_table+0x10,%rax)
> - RELOCATE_MEM(compat_pg_table+0x18,%rax)
> -
> - /*
> - * Setup an identity mapped region in PML4[0] of idle page
> - * table.
> - */
> - RELOCATE_SYM(l3_identmap,%rax)
> - or $0x63,%rax
> - mov %rax, idle_pg_table(%rip)
> -
> - /* Switch to idle page table. */
> - RELOCATE_SYM(idle_pg_table,%rax)
> - movq %rax, %cr3
> -
> - /* Switch to identity mapped compatibility stack. */
> - RELOCATE_SYM(compat_stack,%rax)
> - movq %rax, %rsp
> -
> - /* Save xen_phys_start for 32 bit code. */
> - movq xen_phys_start(%rip), %rbx
> -
> - /* Jump to low identity mapping in compatibility mode. */
> - ljmp *compatibility_mode_far(%rip)
> - ud2
> -
> -compatibility_mode_far:
> - .long SYM_PHYS(compatibility_mode)
> - .long __HYPERVISOR_CS32
> -
> - /*
> - * We use 5 words of stack for the arguments passed to the kernel. The
> - * kernel only uses 1 word before switching to its own stack. Allocate
> - * 16 words to give "plenty" of room.
> - */
> - .fill 16,4,0
> -compat_stack:
> -
> - .code32
> -
> -#undef RELOCATE_SYM
> -#undef RELOCATE_MEM
> -
> -/*
> - * Load physical address of symbol into register and relocate it. %rbx
> - * contains xen_phys_start(%rip) saved before jump to compatibility
> - * mode.
> - */
> -#define RELOCATE_SYM(sym,reg) mov $SYM_PHYS(sym), reg ; \
> - add %ebx, reg
> -
> -compatibility_mode:
> - /* Setup some sane segments. */
> - movl $__HYPERVISOR_DS32, %eax
> - movl %eax, %ds
> - movl %eax, %es
> - movl %eax, %fs
> - movl %eax, %gs
> - movl %eax, %ss
> -
> - /* Push arguments onto stack. */
> - pushl $0 /* 20(%esp) - preserve context */
> - pushl $1 /* 16(%esp) - cpu has pae */
> - pushl %ecx /* 12(%esp) - start address */
> - pushl %edx /* 8(%esp) - page list */
> - pushl %esi /* 4(%esp) - indirection page */
> - pushl %edi /* 0(%esp) - CALL */
> -
> - /* Disable paging and therefore leave 64 bit mode. */
> - movl %cr0, %eax
> - andl $~X86_CR0_PG, %eax
> - movl %eax, %cr0
> -
> - /* Switch to 32 bit page table. */
> - RELOCATE_SYM(compat_pg_table, %eax)
> - movl %eax, %cr3
> -
> - /* Clear MSR_EFER[LME], disabling long mode */
> - movl $MSR_EFER,%ecx
> - rdmsr
> - btcl $_EFER_LME,%eax
> - wrmsr
> -
> - /* Re-enable paging, but only 32 bit mode now. */
> - movl %cr0, %eax
> - orl $X86_CR0_PG, %eax
> - movl %eax, %cr0
> - jmp 1f
> -1:
> -
> - popl %eax
> - call *%eax
> - ud2
> -
> - .data
> - .align 4
> -compat_page_list:
> - .fill 12,4,0
> -
> - .align 32,0
> -
> - /*
> - * These compat page tables contain an identity mapping of the
> - * first 4G of the physical address space.
> - */
> -compat_pg_table:
> - .long SYM_PHYS(compat_pg_table_l2) + 0*PAGE_SIZE + 0x01, 0
> - .long SYM_PHYS(compat_pg_table_l2) + 1*PAGE_SIZE + 0x01, 0
> - .long SYM_PHYS(compat_pg_table_l2) + 2*PAGE_SIZE + 0x01, 0
> - .long SYM_PHYS(compat_pg_table_l2) + 3*PAGE_SIZE + 0x01, 0
> -
> - .section .data.page_aligned, "aw", @progbits
> - .align PAGE_SIZE,0
> -compat_pg_table_l2:
> - .macro identmap from=0, count=512
> - .if \count-1
> - identmap "(\from+0)","(\count/2)"
> - identmap "(\from+(0x200000*(\count/2)))","(\count/2)"
> - .else
> - .quad 0x00000000000000e3 + \from
> - .endif
> - .endm
> -
> - identmap 0x00000000
> - identmap 0x40000000
> - identmap 0x80000000
> - identmap 0xc0000000
> diff --git a/xen/arch/x86/x86_64/kexec_reloc.S b/xen/arch/x86/x86_64/kexec_reloc.S
> new file mode 100644
> index 0000000..7a16c85
> --- /dev/null
> +++ b/xen/arch/x86/x86_64/kexec_reloc.S
> @@ -0,0 +1,198 @@
> +/*
> + * Relocate a kexec_image to its destination and call it.
> + *
> + * Copyright (C) 2013 Citrix Systems R&D Ltd.
> + *
> + * Portions derived from Linux's arch/x86/kernel/relocate_kernel_64.S.
> + *
> + * Copyright (C) 2002-2005 Eric Biederman <ebiederm at xmission.com>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2. See the file COPYING for more details.
> + */
> +#include <xen/config.h>
> +#include <xen/kimage.h>
> +
> +#include <asm/asm_defns.h>
> +#include <asm/msr.h>
> +#include <asm/page.h>
> +#include <asm/machine_kexec.h>
> +
> + .text
> + .align PAGE_SIZE
> + .code64
> +
> +ENTRY(kexec_reloc)
> + /* %rdi - code page maddr */
> + /* %rsi - page table maddr */
> + /* %rdx - indirection page maddr */
> + /* %rcx - entry maddr (%rbp) */
> + /* %r8 - flags */
> +
> + movq %rcx, %rbp
> +
> + /* Setup stack. */
> + leaq (reloc_stack - kexec_reloc)(%rdi), %rsp
> +
> + /* Load reloc page table. */
> + movq %rsi, %cr3
> +
> + /* Jump to identity mapped code. */
> + leaq (identity_mapped - kexec_reloc)(%rdi), %rax
> + jmpq *%rax
> +
> +identity_mapped:
> + /*
> + * Set cr0 to a known state:
> + * - Paging enabled
> + * - Alignment check disabled
> + * - Write protect disabled
> + * - No task switch
> + * - Don't do FP software emulation.
> + * - Protected mode enabled
> + */
> + movq %cr0, %rax
> + andl $~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %eax
> + orl $(X86_CR0_PG | X86_CR0_PE), %eax
> + movq %rax, %cr0
> +
> + /*
> + * Set cr4 to a known state:
> + * - physical address extension enabled
> + */
> + movl $X86_CR4_PAE, %eax
> + movq %rax, %cr4
> +
> + movq %rdx, %rdi
> + call relocate_pages
> +
> + /* Need to switch to 32-bit mode? */
> + testq $KEXEC_RELOC_FLAG_COMPAT, %r8
> + jnz call_32_bit
> +
> +call_64_bit:
> + /* Call the image entry point. This should never return. */
> + callq *%rbp
> + ud2
> +
> +call_32_bit:
> + /* Setup IDT. */
> + lidt compat_mode_idt(%rip)
> +
> + /* Load compat GDT. */
> + leaq compat_mode_gdt(%rip), %rax
> + movq %rax, (compat_mode_gdt_desc + 2)(%rip)
> + lgdt compat_mode_gdt_desc(%rip)
> +
> + /* Relocate compatibility mode entry point address. */
> + leal compatibility_mode(%rip), %eax
> + movl %eax, compatibility_mode_far(%rip)
> +
> + /* Enter compatibility mode. */
> + ljmp *compatibility_mode_far(%rip)
> +
> +relocate_pages:
> + /* %rdi - indirection page maddr */
> + pushq %rbx
> +
> + cld
> + movq %rdi, %rbx
> + xorl %edi, %edi
> + xorl %esi, %esi
> +
> +next_entry: /* top, read another word for the indirection page */
> +
> + movq (%rbx), %rcx
> + addq $8, %rbx
> +is_dest:
> + testb $IND_DESTINATION, %cl
> + jz is_ind
> + movq %rcx, %rdi
> + andq $PAGE_MASK, %rdi
> + jmp next_entry
> +is_ind:
> + testb $IND_INDIRECTION, %cl
> + jz is_done
> + movq %rcx, %rbx
> + andq $PAGE_MASK, %rbx
> + jmp next_entry
> +is_done:
> + testb $IND_DONE, %cl
> + jnz done
> +is_source:
> + testb $IND_SOURCE, %cl
> + jz is_zero
> + movq %rcx, %rsi /* For every source page do a copy */
> + andq $PAGE_MASK, %rsi
> + movl $(PAGE_SIZE / 8), %ecx
> + rep movsq
> + jmp next_entry
> +is_zero:
> + testb $IND_ZERO, %cl
> + jz next_entry
> + movl $(PAGE_SIZE / 8), %ecx /* Zero the destination page. */
> + xorl %eax, %eax
> + rep stosq
> + jmp next_entry
> +done:
> + popq %rbx
> + ret
> +
> + .code32
> +
> +compatibility_mode:
> + /* Setup some sane segments. */
> + movl $0x0008, %eax
> + movl %eax, %ds
> + movl %eax, %es
> + movl %eax, %fs
> + movl %eax, %gs
> + movl %eax, %ss
> +
> + /* Disable paging and therefore leave 64 bit mode. */
> + movl %cr0, %eax
> + andl $~X86_CR0_PG, %eax
> + movl %eax, %cr0
> +
> + /* Disable long mode */
> + movl $MSR_EFER, %ecx
> + rdmsr
> + andl $~EFER_LME, %eax
> + wrmsr
> +
> + /* Clear cr4 to disable PAE. */
> + xorl %eax, %eax
> + movl %eax, %cr4
> +
> + /* Call the image entry point. This should never return. */
> + call *%ebp
> + ud2
> +
> + .align 4
> +compatibility_mode_far:
> + .long 0x00000000 /* set in call_32_bit above */
> + .word 0x0010
> +
> +compat_mode_gdt_desc:
> + .word (3*8)-1
> + .quad 0x0000000000000000 /* set in call_32_bit above */
> +
> + .align 8
> +compat_mode_gdt:
> + .quad 0x0000000000000000 /* null */
> + .quad 0x00cf92000000ffff /* 0x0008 ring 0 data */
> + .quad 0x00cf9a000000ffff /* 0x0010 ring 0 code, compatibility */
> +
> +compat_mode_idt:
> + .word 0 /* limit */
> + .long 0 /* base */
> +
> + /*
> + * 16 words of stack are more than enough.
> + */
> + .fill 16,8,0
> +reloc_stack:
> +
> + .globl kexec_reloc_size
> +kexec_reloc_size:
> + .long . - kexec_reloc
> diff --git a/xen/common/kexec.c b/xen/common/kexec.c
> index 7b23df0..c5450ba 100644
> --- a/xen/common/kexec.c
> +++ b/xen/common/kexec.c
> @@ -25,6 +25,7 @@
> #include <xen/version.h>
> #include <xen/console.h>
> #include <xen/kexec.h>
> +#include <xen/kimage.h>
> #include <public/elfnote.h>
> #include <xsm/xsm.h>
> #include <xen/cpu.h>
> @@ -47,7 +48,7 @@ static Elf_Note *xen_crash_note;
>
> static cpumask_t crash_saved_cpus;
>
> -static xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
> +static struct kexec_image *kexec_image[KEXEC_IMAGE_NR];
>
> #define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0)
> #define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1)
> @@ -55,8 +56,6 @@ static xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR];
>
> static unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */
>
> -static spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED;
> -
> static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
> static size_t vmcoreinfo_size = 0;
>
> @@ -311,14 +310,14 @@ void kexec_crash(void)
> kexec_common_shutdown();
> kexec_crash_save_cpu();
> machine_crash_shutdown();
> - machine_kexec(&kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]);
> + machine_kexec(kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]);
>
> BUG();
> }
>
> static long kexec_reboot(void *_image)
> {
> - xen_kexec_image_t *image = _image;
> + struct kexec_image *image = _image;
>
> kexecing = TRUE;
>
> @@ -734,63 +733,264 @@ static void crash_save_vmcoreinfo(void)
> #endif
> }
>
> -static int kexec_load_unload_internal(unsigned long op, xen_kexec_load_v1_t *load)
> +static void kexec_unload_image(struct kexec_image *image)
> {
> - xen_kexec_image_t *image;
> + if ( !image )
> + return;
> +
> + machine_kexec_unload(image);
> + kimage_free(image);
> +}
> +
> +static int kexec_exec(XEN_GUEST_HANDLE_PARAM(void) uarg)
> +{
> + xen_kexec_exec_t exec;
> + struct kexec_image *image;
> + int base, bit, pos, ret = -EINVAL;
> +
> + if ( unlikely(copy_from_guest(&exec, uarg, 1)) )
> + return -EFAULT;
> +
> + if ( kexec_load_get_bits(exec.type, &base, &bit) )
> + return -EINVAL;
> +
> + pos = (test_bit(bit, &kexec_flags) != 0);
> +
> + /* Only allow kexec/kdump into loaded images */
> + if ( !test_bit(base + pos, &kexec_flags) )
> + return -ENOENT;
> +
> + switch (exec.type)
> + {
> + case KEXEC_TYPE_DEFAULT:
> + image = kexec_image[base + pos];
> + ret = continue_hypercall_on_cpu(0, kexec_reboot, image);
> + break;
> + case KEXEC_TYPE_CRASH:
> + kexec_crash(); /* Does not return */
> + break;
> + }
> +
> + return -EINVAL; /* never reached */
> +}
> +
> +static int kexec_swap_images(int type, struct kexec_image *new,
> + struct kexec_image **old)
> +{
> + static DEFINE_SPINLOCK(kexec_lock);
> int base, bit, pos;
> - int ret = 0;
> + int new_slot, old_slot;
> +
> + *old = NULL;
> +
> + spin_lock(&kexec_lock);
> +
> + if ( test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
> + {
> + spin_unlock(&kexec_lock);
> + return -EBUSY;
> + }
>
> - if ( kexec_load_get_bits(load->type, &base, &bit) )
> + if ( kexec_load_get_bits(type, &base, &bit) )
> return -EINVAL;
>
> pos = (test_bit(bit, &kexec_flags) != 0);
> + old_slot = base + pos;
> + new_slot = base + !pos;
>
> - /* Load the user data into an unused image */
> - if ( op == KEXEC_CMD_kexec_load )
> + if ( new )
> {
> - image = &kexec_image[base + !pos];
> + kexec_image[new_slot] = new;
> + set_bit(new_slot, &kexec_flags);
> + }
> + change_bit(bit, &kexec_flags);
>
> - BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */
> + clear_bit(old_slot, &kexec_flags);
> + *old = kexec_image[old_slot];
>
> - memcpy(image, &load->image, sizeof(*image));
> + spin_unlock(&kexec_lock);
>
> - if ( !(ret = machine_kexec_load(load->type, base + !pos, image)) )
> - {
> - /* Set image present bit */
> - set_bit((base + !pos), &kexec_flags);
> + return 0;
> +}
>
> - /* Make new image the active one */
> - change_bit(bit, &kexec_flags);
> - }
> +static int kexec_load_slot(struct kexec_image *kimage)
> +{
> + struct kexec_image *old_kimage;
> + int ret = -ENOMEM;
> +
> + ret = machine_kexec_load(kimage);
> + if ( ret < 0 )
> + return ret;
> +
> + crash_save_vmcoreinfo();
> +
> + ret = kexec_swap_images(kimage->type, kimage, &old_kimage);
> + if ( ret < 0 )
> + return ret;
> +
> + kexec_unload_image(old_kimage);
> +
> + return 0;
> +}
> +
> +static uint16_t kexec_load_v1_arch(void)
> +{
> +#ifdef CONFIG_X86
> + return is_pv_32on64_domain(dom0) ? EM_386 : EM_X86_64;
> +#else
> + return EM_NONE;
> +#endif
> +}
>
> - crash_save_vmcoreinfo();
> +static int kexec_segments_add_segment(
> + unsigned int *nr_segments, xen_kexec_segment_t *segments,
> + unsigned long mfn)
> +{
> + paddr_t maddr = (paddr_t)mfn << PAGE_SHIFT;
> + unsigned int n = *nr_segments;
> +
> + /* Need a new segment? */
> + if ( n == 0
> + || segments[n-1].dest_maddr + segments[n-1].dest_size != maddr )
> + {
> + n++;
> + if ( n > KEXEC_SEGMENT_MAX )
> + return -EINVAL;
> + *nr_segments = n;
> +
> + set_xen_guest_handle(segments[n-1].buf.h, NULL);
> + segments[n-1].buf_size = 0;
> + segments[n-1].dest_maddr = maddr;
> + segments[n-1].dest_size = 0;
> }
>
> - /* Unload the old image if present and load successful */
> - if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) )
> + return 0;
> +}
> +
> +static int kexec_segments_from_ind_page(unsigned long mfn,
> + unsigned int *nr_segments,
> + xen_kexec_segment_t *segments,
> + bool_t compat)
> +{
> + void *page;
> + kimage_entry_t *entry;
> + int ret = 0;
> +
> + page = map_domain_page(mfn);
> +
> + /*
> + * Walk the indirection page list, adding destination pages to the
> + * segments.
> + */
> + for ( entry = page; ; )
> {
> - if ( test_and_clear_bit((base + pos), &kexec_flags) )
> + unsigned long ind;
> +
> + ind = kimage_entry_ind(entry, compat);
> + mfn = kimage_entry_mfn(entry, compat);
> +
> + switch ( ind )
> {
> - image = &kexec_image[base + pos];
> - machine_kexec_unload(load->type, base + pos, image);
> + case IND_DESTINATION:
> + ret = kexec_segments_add_segment(nr_segments, segments, mfn);
> + if ( ret < 0 )
> + goto done;
> + break;
> + case IND_INDIRECTION:
> + unmap_domain_page(page);
> + entry = page = map_domain_page(mfn);
> + continue;
> + case IND_DONE:
> + goto done;
> + case IND_SOURCE:
> + if ( *nr_segments == 0 )
> + {
> + ret = -EINVAL;
> + goto done;
> + }
> + segments[*nr_segments-1].dest_size += PAGE_SIZE;
> + break;
> + default:
> + ret = -EINVAL;
> + goto done;
> }
> + entry = kimage_entry_next(entry, compat);
> }
> +done:
> + unmap_domain_page(page);
> + return ret;
> +}
>
> +static int kexec_do_load_v1(xen_kexec_load_v1_t *load, int compat)
> +{
> + struct kexec_image *kimage = NULL;
> + xen_kexec_segment_t *segments;
> + uint16_t arch;
> + unsigned int nr_segments = 0;
> + unsigned long ind_mfn = load->image.indirection_page >> PAGE_SHIFT;
> + int ret;
> +
> + arch = kexec_load_v1_arch();
> + if ( arch == EM_NONE )
> + return -ENOSYS;
> +
> + segments = xmalloc_array(xen_kexec_segment_t, KEXEC_SEGMENT_MAX);
> + if ( segments == NULL )
> + return -ENOMEM;
> +
> + /*
> + * Work out the image segments (destination only) from the
> + * indirection pages.
> + *
> + * This is needed so we don't allocate pages that will overlap
> + * with the destination when building the new set of indirection
> + * pages below.
> + */
> + ret = kexec_segments_from_ind_page(ind_mfn, &nr_segments, segments, compat);
> + if ( ret < 0 )
> + goto error;
> +
> + ret = kimage_alloc(&kimage, load->type, arch, load->image.start_address,
> + nr_segments, segments);
> + if ( ret < 0 )
> + goto error;
> +
> + /*
> + * Build a new set of indirection pages in the native format.
> + *
> + * This walks the guest provided indirection pages a second time.
> + * The guest could have altered then, invalidating the segment
> + * information constructed above. This will only result in the
> + * resulting image being potentially unrelocatable.
> + */
> + ret = kimage_build_ind(kimage, ind_mfn, compat);
> + if ( ret < 0 )
> + goto error;
> +
> + ret = kexec_load_slot(kimage);
> + if ( ret < 0 )
> + goto error;
> +
> + return 0;
> +
> +error:
> + if ( !kimage )
> + xfree(segments);
> + kimage_free(kimage);
> return ret;
> }
>
> -static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) uarg)
> +static int kexec_load_v1(XEN_GUEST_HANDLE_PARAM(void) uarg)
> {
> xen_kexec_load_v1_t load;
>
> if ( unlikely(copy_from_guest(&load, uarg, 1)) )
> return -EFAULT;
>
> - return kexec_load_unload_internal(op, &load);
> + return kexec_do_load_v1(&load, 0);
> }
>
> -static int kexec_load_unload_compat(unsigned long op,
> - XEN_GUEST_HANDLE_PARAM(void) uarg)
> +static int kexec_load_v1_compat(XEN_GUEST_HANDLE_PARAM(void) uarg)
> {
> #ifdef CONFIG_COMPAT
> compat_kexec_load_v1_t compat_load;
> @@ -809,49 +1009,113 @@ static int kexec_load_unload_compat(unsigned long op,
> load.type = compat_load.type;
> XLAT_kexec_image(&load.image, &compat_load.image);
>
> - return kexec_load_unload_internal(op, &load);
> -#else /* CONFIG_COMPAT */
> + return kexec_do_load_v1(&load, 1);
> +#else
> return 0;
> -#endif /* CONFIG_COMPAT */
> +#endif
> }
>
> -static int kexec_exec(XEN_GUEST_HANDLE_PARAM(void) uarg)
> +static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) uarg)
> {
> - xen_kexec_exec_t exec;
> - xen_kexec_image_t *image;
> - int base, bit, pos, ret = -EINVAL;
> + xen_kexec_load_t load;
> + xen_kexec_segment_t *segments;
> + struct kexec_image *kimage = NULL;
> + int ret;
>
> - if ( unlikely(copy_from_guest(&exec, uarg, 1)) )
> + if ( copy_from_guest(&load, uarg, 1) )
> return -EFAULT;
>
> - if ( kexec_load_get_bits(exec.type, &base, &bit) )
> + if ( load.nr_segments >= KEXEC_SEGMENT_MAX )
> return -EINVAL;
>
> - pos = (test_bit(bit, &kexec_flags) != 0);
> -
> - /* Only allow kexec/kdump into loaded images */
> - if ( !test_bit(base + pos, &kexec_flags) )
> - return -ENOENT;
> + segments = xmalloc_array(xen_kexec_segment_t, load.nr_segments);
> + if ( segments == NULL )
> + return -ENOMEM;
>
> - switch (exec.type)
> + if ( copy_from_guest(segments, load.segments.h, load.nr_segments) )
> {
> - case KEXEC_TYPE_DEFAULT:
> - image = &kexec_image[base + pos];
> - ret = continue_hypercall_on_cpu(0, kexec_reboot, image);
> - break;
> - case KEXEC_TYPE_CRASH:
> - kexec_crash(); /* Does not return */
> - break;
> + ret = -EFAULT;
> + goto error;
> }
>
> - return -EINVAL; /* never reached */
> + ret = kimage_alloc(&kimage, load.type, load.arch, load.entry_maddr,
> + load.nr_segments, segments);
> + if ( ret < 0 )
> + goto error;
> +
> + ret = kimage_load_segments(kimage);
> + if ( ret < 0 )
> + goto error;
> +
> + ret = kexec_load_slot(kimage);
> + if ( ret < 0 )
> + goto error;
> +
> + return 0;
> +
> +error:
> + if ( ! kimage )
> + xfree(segments);
> + kimage_free(kimage);
> + return ret;
> +}
> +
> +static int kexec_do_unload(xen_kexec_unload_t *unload)
> +{
> + struct kexec_image *old_kimage;
> + int ret;
> +
> + ret = kexec_swap_images(unload->type, NULL, &old_kimage);
> + if ( ret < 0 )
> + return ret;
> +
> + kexec_unload_image(old_kimage);
> +
> + return 0;
> +}
> +
> +static int kexec_unload_v1(XEN_GUEST_HANDLE_PARAM(void) uarg)
> +{
> + xen_kexec_load_v1_t load;
> + xen_kexec_unload_t unload;
> +
> + if ( copy_from_guest(&load, uarg, 1) )
> + return -EFAULT;
> +
> + unload.type = load.type;
> + return kexec_do_unload(&unload);
> +}
> +
> +static int kexec_unload_v1_compat(XEN_GUEST_HANDLE_PARAM(void) uarg)
> +{
> +#ifdef CONFIG_COMPAT
> + compat_kexec_load_v1_t compat_load;
> + xen_kexec_unload_t unload;
> +
> + if ( copy_from_guest(&compat_load, uarg, 1) )
> + return -EFAULT;
> +
> + unload.type = compat_load.type;
> + return kexec_do_unload(&unload);
> +#else
> + return 0;
> +#endif
> +}
> +
> +static int kexec_unload(XEN_GUEST_HANDLE_PARAM(void) uarg)
> +{
> + xen_kexec_unload_t unload;
> +
> + if ( unlikely(copy_from_guest(&unload, uarg, 1)) )
> + return -EFAULT;
> +
> + return kexec_do_unload(&unload);
> }
>
> static int do_kexec_op_internal(unsigned long op,
> XEN_GUEST_HANDLE_PARAM(void) uarg,
> bool_t compat)
> {
> - unsigned long flags;
> int ret = -EINVAL;
>
> ret = xsm_kexec(XSM_PRIV);
> @@ -867,20 +1131,26 @@ static int do_kexec_op_internal(unsigned long op,
> ret = kexec_get_range(uarg);
> break;
> case KEXEC_CMD_kexec_load_v1:
> + if ( compat )
> + ret = kexec_load_v1_compat(uarg);
> + else
> + ret = kexec_load_v1(uarg);
> + break;
> case KEXEC_CMD_kexec_unload_v1:
> - spin_lock_irqsave(&kexec_lock, flags);
> - if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags))
> - {
> - if (compat)
> - ret = kexec_load_unload_compat(op, uarg);
> - else
> - ret = kexec_load_unload(op, uarg);
> - }
> - spin_unlock_irqrestore(&kexec_lock, flags);
> + if ( compat )
> + ret = kexec_unload_v1_compat(uarg);
> + else
> + ret = kexec_unload_v1(uarg);
> break;
> case KEXEC_CMD_kexec:
> ret = kexec_exec(uarg);
> break;
> + case KEXEC_CMD_kexec_load:
> + ret = kexec_load(uarg);
> + break;
> + case KEXEC_CMD_kexec_unload:
> + ret = kexec_unload(uarg);
> + break;
> }
>
> return ret;
> diff --git a/xen/common/kimage.c b/xen/common/kimage.c
> index 02ee37e..10fb785 100644
> --- a/xen/common/kimage.c
> +++ b/xen/common/kimage.c
> @@ -175,11 +175,20 @@ static int do_kimage_alloc(struct kexec_image **rimage, paddr_t entry,
> image->control_code_page = kimage_alloc_control_page(image, MEMF_bits(32));
> if ( !image->control_code_page )
> goto out;
> + result = machine_kexec_add_page(image,
> + page_to_maddr(image->control_code_page),
> + page_to_maddr(image->control_code_page));
> + if ( result < 0 )
> + goto out;
>
> /* Add an empty indirection page. */
> image->entry_page = kimage_alloc_control_page(image, 0);
> if ( !image->entry_page )
> goto out;
> + result = machine_kexec_add_page(image, page_to_maddr(image->entry_page),
> + page_to_maddr(image->entry_page));
> + if ( result < 0 )
> + goto out;
>
> image->head = page_to_maddr(image->entry_page);
>
> @@ -595,7 +604,7 @@ static struct page_info *kimage_alloc_page(struct kexec_image *image,
> if ( addr == destination )
> {
> page_list_del(page, &image->dest_pages);
> - return page;
> + goto found;
> }
> }
> page = NULL;
> @@ -647,6 +656,8 @@ static struct page_info *kimage_alloc_page(struct kexec_image *image,
> page_list_add(page, &image->dest_pages);
> }
> }
> +found:
> + machine_kexec_add_page(image, page_to_maddr(page), page_to_maddr(page));
> return page;
> }
>
> @@ -753,6 +764,7 @@ static int kimage_load_crash_segment(struct kexec_image *image,
> static int kimage_load_segment(struct kexec_image *image, xen_kexec_segment_t *segment)
> {
> int result = -ENOMEM;
> + paddr_t addr;
>
> if ( !guest_handle_is_null(segment->buf.h) )
> {
> @@ -767,6 +779,14 @@ static int kimage_load_segment(struct kexec_image *image, xen_kexec_segment_t *s
> }
> }
>
> + for ( addr = segment->dest_maddr & PAGE_MASK;
> + addr < segment->dest_maddr + segment->dest_size; addr += PAGE_SIZE )
> + {
> + result = machine_kexec_add_page(image, addr, addr);
> + if ( result < 0 )
> + break;
> + }
> +
> return result;
> }
>
> @@ -810,6 +830,106 @@ int kimage_load_segments(struct kexec_image *image)
> return 0;
> }
>
> +kimage_entry_t *kimage_entry_next(kimage_entry_t *entry, bool_t compat)
> +{
> + if ( compat )
> + return (kimage_entry_t *)((uint32_t *)entry + 1);
> + return entry + 1;
> +}
> +
> +unsigned long kimage_entry_mfn(kimage_entry_t *entry, bool_t compat)
> +{
> + if ( compat )
> + return *(uint32_t *)entry >> PAGE_SHIFT;
> + return *entry >> PAGE_SHIFT;
> +}
> +
> +unsigned long kimage_entry_ind(kimage_entry_t *entry, bool_t compat)
> +{
> + if ( compat )
> + return *(uint32_t *)entry & 0xf;
> + return *entry & 0xf;
> +}
> +
> +int kimage_build_ind(struct kexec_image *image, unsigned long ind_mfn,
> + bool_t compat)
> +{
> + void *page;
> + kimage_entry_t *entry;
> + int ret = 0;
> + paddr_t dest = KIMAGE_NO_DEST;
> +
> + page = map_domain_page(ind_mfn);
> + if ( !page )
> + return -ENOMEM;
> +
> + /*
> + * Walk the guest-supplied indirection pages, adding entries to
> + * the image's indirection pages.
> + */
> + for ( entry = page; ; )
> + {
> + unsigned long ind;
> + unsigned long mfn;
> +
> + ind = kimage_entry_ind(entry, compat);
> + mfn = kimage_entry_mfn(entry, compat);
> +
> + switch ( ind )
> + {
> + case IND_DESTINATION:
> + dest = (paddr_t)mfn << PAGE_SHIFT;
> + ret = kimage_set_destination(image, dest);
> + if ( ret < 0 )
> + goto done;
> + break;
> + case IND_INDIRECTION:
> + unmap_domain_page(page);
> + page = map_domain_page(mfn);
> + entry = page;
> + continue;
> + case IND_DONE:
> + kimage_terminate(image);
> + goto done;
> + case IND_SOURCE:
> + {
> + struct page_info *guest_page, *xen_page;
> +
> + guest_page = mfn_to_page(mfn);
> + if ( !get_page(guest_page, current->domain) )
> + {
> + ret = -EFAULT;
> + goto done;
> + }
> +
> + xen_page = kimage_alloc_page(image, dest);
> + if ( !xen_page )
> + {
> + put_page(guest_page);
> + ret = -ENOMEM;
> + goto done;
> + }
> +
> + copy_domain_page(page_to_mfn(xen_page), mfn);
> + put_page(guest_page);
> +
> + ret = kimage_add_page(image, page_to_maddr(xen_page));
> + if ( ret < 0 )
> + goto done;
> + dest += PAGE_SIZE;
> + break;
> + }
> + default:
> + ret = -EINVAL;
> + goto done;
> + }
> + entry = kimage_entry_next(entry, compat);
> + }
> +done:
> + unmap_domain_page(page);
> + return ret;
> +}
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h
> index 8b4266d..48c5676 100644
> --- a/xen/include/asm-x86/fixmap.h
> +++ b/xen/include/asm-x86/fixmap.h
> @@ -56,9 +56,6 @@ enum fixed_addresses {
> FIX_ACPI_BEGIN,
> FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
> FIX_HPET_BASE,
> - FIX_KEXEC_BASE_0,
> - FIX_KEXEC_BASE_END = FIX_KEXEC_BASE_0 \
> - + ((KEXEC_XEN_NO_PAGES >> 1) * KEXEC_IMAGE_NR) - 1,
> FIX_TBOOT_SHARED_BASE,
> FIX_MSIX_IO_RESERV_BASE,
> FIX_MSIX_IO_RESERV_END = FIX_MSIX_IO_RESERV_BASE + FIX_MSIX_MAX_PAGES -1,
> diff --git a/xen/include/asm-x86/machine_kexec.h b/xen/include/asm-x86/machine_kexec.h
> new file mode 100644
> index 0000000..ba0d469
> --- /dev/null
> +++ b/xen/include/asm-x86/machine_kexec.h
> @@ -0,0 +1,16 @@
> +#ifndef __X86_MACHINE_KEXEC_H__
> +#define __X86_MACHINE_KEXEC_H__
> +
> +#define KEXEC_RELOC_FLAG_COMPAT 0x1 /* 32-bit image */
> +
> +#ifndef __ASSEMBLY__
> +
> +extern void kexec_reloc(unsigned long reloc_code, unsigned long reloc_pt,
> + unsigned long ind_maddr, unsigned long entry_maddr,
> + unsigned long flags);
> +
> +extern unsigned int kexec_reloc_size;
> +
> +#endif
> +
> +#endif /* __X86_MACHINE_KEXEC_H__ */
> diff --git a/xen/include/xen/kexec.h b/xen/include/xen/kexec.h
> index 1a5dda1..bd17747 100644
> --- a/xen/include/xen/kexec.h
> +++ b/xen/include/xen/kexec.h
> @@ -6,6 +6,7 @@
> #include <public/kexec.h>
> #include <asm/percpu.h>
> #include <xen/elfcore.h>
> +#include <xen/kimage.h>
>
> typedef struct xen_kexec_reserve {
> unsigned long size;
> @@ -40,11 +41,13 @@ extern enum low_crashinfo low_crashinfo_mode;
> extern paddr_t crashinfo_maxaddr_bits;
> void kexec_early_calculations(void);
>
> -int machine_kexec_load(int type, int slot, xen_kexec_image_t *image);
> -void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image);
> +int machine_kexec_add_page(struct kexec_image *image, unsigned long vaddr,
> + unsigned long maddr);
> +int machine_kexec_load(struct kexec_image *image);
> +void machine_kexec_unload(struct kexec_image *image);
> void machine_kexec_reserved(xen_kexec_reserve_t *reservation);
> -void machine_reboot_kexec(xen_kexec_image_t *image);
> -void machine_kexec(xen_kexec_image_t *image);
> +void machine_reboot_kexec(struct kexec_image *image);
> +void machine_kexec(struct kexec_image *image);
> void kexec_crash(void);
> void kexec_crash_save_cpu(void);
> crash_xen_info_t *kexec_crash_save_info(void);
> @@ -52,11 +55,6 @@ void machine_crash_shutdown(void);
> int machine_kexec_get(xen_kexec_range_t *range);
> int machine_kexec_get_xen(xen_kexec_range_t *range);
>
> -void compat_machine_kexec(unsigned long rnk,
> - unsigned long indirection_page,
> - unsigned long *page_list,
> - unsigned long start_address);
> -
> /* vmcoreinfo stuff */
> #define VMCOREINFO_BYTES (4096)
> #define VMCOREINFO_NOTE_NAME "VMCOREINFO_XEN"
> diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h
> index 0ebd37a..d10ebf7 100644
> --- a/xen/include/xen/kimage.h
> +++ b/xen/include/xen/kimage.h
> @@ -47,6 +47,12 @@ int kimage_load_segments(struct kexec_image *image);
> struct page_info *kimage_alloc_control_page(struct kexec_image *image,
> unsigned memflags);
>
> +kimage_entry_t *kimage_entry_next(kimage_entry_t *entry, bool_t compat);
> +unsigned long kimage_entry_mfn(kimage_entry_t *entry, bool_t compat);
> +unsigned long kimage_entry_ind(kimage_entry_t *entry, bool_t compat);
> +int kimage_build_ind(struct kexec_image *image, unsigned long ind_mfn,
> + bool_t compat);
> +
> #endif /* __ASSEMBLY__ */
>
> #endif /* __XEN_KIMAGE_H__ */
More information about the kexec
mailing list