ia64/linux-2.6.18-xen.hg

changeset 4:1c0aeb8749d2

Imported patch git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch from xen-unstable.hg 15200:bd3d6b4c52ec
author Ian Campbell <ian.campbell@xensource.com>
date Mon Jun 04 10:05:23 2007 +0100 (2007-06-04)
parents 948d16bbacc2
children 405dae994591
files arch/x86_64/kernel/machine_kexec.c arch/x86_64/kernel/relocate_kernel.S include/asm-x86_64/kexec.h
line diff
     1.1 --- a/arch/x86_64/kernel/machine_kexec.c	Mon Jun 04 10:05:23 2007 +0100
     1.2 +++ b/arch/x86_64/kernel/machine_kexec.c	Mon Jun 04 10:05:23 2007 +0100
     1.3 @@ -15,6 +15,15 @@
     1.4  #include <asm/mmu_context.h>
     1.5  #include <asm/io.h>
     1.6  
     1.7 +#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
     1.8 +static u64 kexec_pgd[512] PAGE_ALIGNED;
     1.9 +static u64 kexec_pud0[512] PAGE_ALIGNED;
    1.10 +static u64 kexec_pmd0[512] PAGE_ALIGNED;
    1.11 +static u64 kexec_pte0[512] PAGE_ALIGNED;
    1.12 +static u64 kexec_pud1[512] PAGE_ALIGNED;
    1.13 +static u64 kexec_pmd1[512] PAGE_ALIGNED;
    1.14 +static u64 kexec_pte1[512] PAGE_ALIGNED;
    1.15 +
    1.16  static void init_level2_page(pmd_t *level2p, unsigned long addr)
    1.17  {
    1.18  	unsigned long end_addr;
    1.19 @@ -144,32 +153,19 @@ static void load_segments(void)
    1.20  		);
    1.21  }
    1.22  
    1.23 -typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page,
    1.24 -					unsigned long control_code_buffer,
    1.25 -					unsigned long start_address,
    1.26 -					unsigned long pgtable) ATTRIB_NORET;
    1.27 -
    1.28 -extern const unsigned char relocate_new_kernel[];
    1.29 -extern const unsigned long relocate_new_kernel_size;
    1.30 -
    1.31  int machine_kexec_prepare(struct kimage *image)
    1.32  {
    1.33 -	unsigned long start_pgtable, control_code_buffer;
    1.34 +	unsigned long start_pgtable;
    1.35  	int result;
    1.36  
    1.37  	/* Calculate the offsets */
    1.38  	start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
    1.39 -	control_code_buffer = start_pgtable + PAGE_SIZE;
    1.40  
    1.41  	/* Setup the identity mapped 64bit page table */
    1.42  	result = init_pgtable(image, start_pgtable);
    1.43  	if (result)
    1.44  		return result;
    1.45  
    1.46 -	/* Place the code in the reboot code buffer */
    1.47 -	memcpy(__va(control_code_buffer), relocate_new_kernel,
    1.48 -						relocate_new_kernel_size);
    1.49 -
    1.50  	return 0;
    1.51  }
    1.52  
    1.53 @@ -184,28 +180,34 @@ void machine_kexec_cleanup(struct kimage
    1.54   */
    1.55  NORET_TYPE void machine_kexec(struct kimage *image)
    1.56  {
    1.57 -	unsigned long page_list;
    1.58 -	unsigned long control_code_buffer;
    1.59 -	unsigned long start_pgtable;
    1.60 -	relocate_new_kernel_t rnk;
    1.61 +	unsigned long page_list[PAGES_NR];
    1.62 +	void *control_page;
    1.63  
    1.64  	/* Interrupts aren't acceptable while we reboot */
    1.65  	local_irq_disable();
    1.66  
    1.67 -	/* Calculate the offsets */
    1.68 -	page_list = image->head;
    1.69 -	start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
    1.70 -	control_code_buffer = start_pgtable + PAGE_SIZE;
    1.71 +	control_page = page_address(image->control_code_page) + PAGE_SIZE;
    1.72 +	memcpy(control_page, relocate_kernel, PAGE_SIZE);
    1.73  
    1.74 -	/* Set the low half of the page table to my identity mapped
    1.75 -	 * page table for kexec.  Leave the high half pointing at the
    1.76 -	 * kernel pages.   Don't bother to flush the global pages
    1.77 -	 * as that will happen when I fully switch to my identity mapped
    1.78 -	 * page table anyway.
    1.79 -	 */
    1.80 -	memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2);
    1.81 -	__flush_tlb();
    1.82 +	page_list[PA_CONTROL_PAGE] = __pa(control_page);
    1.83 +	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
    1.84 +	page_list[PA_PGD] = __pa(kexec_pgd);
    1.85 +	page_list[VA_PGD] = (unsigned long)kexec_pgd;
    1.86 +	page_list[PA_PUD_0] = __pa(kexec_pud0);
    1.87 +	page_list[VA_PUD_0] = (unsigned long)kexec_pud0;
    1.88 +	page_list[PA_PMD_0] = __pa(kexec_pmd0);
    1.89 +	page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
    1.90 +	page_list[PA_PTE_0] = __pa(kexec_pte0);
    1.91 +	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
    1.92 +	page_list[PA_PUD_1] = __pa(kexec_pud1);
    1.93 +	page_list[VA_PUD_1] = (unsigned long)kexec_pud1;
    1.94 +	page_list[PA_PMD_1] = __pa(kexec_pmd1);
    1.95 +	page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
    1.96 +	page_list[PA_PTE_1] = __pa(kexec_pte1);
    1.97 +	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
    1.98  
    1.99 +	page_list[PA_TABLE_PAGE] =
   1.100 +	  (unsigned long)__pa(page_address(image->control_code_page));
   1.101  
   1.102  	/* The segment registers are funny things, they have both a
   1.103  	 * visible and an invisible part.  Whenever the visible part is
   1.104 @@ -222,7 +224,8 @@ NORET_TYPE void machine_kexec(struct kim
   1.105  	 */
   1.106  	set_gdt(phys_to_virt(0),0);
   1.107  	set_idt(phys_to_virt(0),0);
   1.108 +
   1.109  	/* now call it */
   1.110 -	rnk = (relocate_new_kernel_t) control_code_buffer;
   1.111 -	(*rnk)(page_list, control_code_buffer, image->start, start_pgtable);
   1.112 +	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
   1.113 +			image->start);
   1.114  }
     2.1 --- a/arch/x86_64/kernel/relocate_kernel.S	Mon Jun 04 10:05:23 2007 +0100
     2.2 +++ b/arch/x86_64/kernel/relocate_kernel.S	Mon Jun 04 10:05:23 2007 +0100
     2.3 @@ -7,31 +7,169 @@
     2.4   */
     2.5  
     2.6  #include <linux/linkage.h>
     2.7 +#include <asm/page.h>
     2.8 +#include <asm/kexec.h>
     2.9  
    2.10 -	/*
    2.11 -	 * Must be relocatable PIC code callable as a C function, that once
    2.12 -	 * it starts can not use the previous processes stack.
    2.13 -	 */
    2.14 -	.globl relocate_new_kernel
    2.15 +/*
    2.16 + * Must be relocatable PIC code callable as a C function
    2.17 + */
    2.18 +
    2.19 +#define PTR(x) (x << 3)
    2.20 +#define PAGE_ALIGNED (1 << PAGE_SHIFT)
    2.21 +#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
    2.22 +
    2.23 +	.text
    2.24 +	.align PAGE_ALIGNED
    2.25  	.code64
    2.26 +	.globl relocate_kernel
    2.27 +relocate_kernel:
    2.28 +	/* %rdi indirection_page
    2.29 +	 * %rsi page_list
    2.30 +	 * %rdx start address
    2.31 +	 */
    2.32 +
    2.33 +	/* map the control page at its virtual address */
    2.34 +
    2.35 +	movq	$0x0000ff8000000000, %r10        /* mask */
    2.36 +	mov	$(39 - 3), %cl                   /* bits to shift */
    2.37 +	movq	PTR(VA_CONTROL_PAGE)(%rsi), %r11 /* address to map */
    2.38 +
    2.39 +	movq	%r11, %r9
    2.40 +	andq	%r10, %r9
    2.41 +	shrq	%cl, %r9
    2.42 +
    2.43 +	movq	PTR(VA_PGD)(%rsi), %r8
    2.44 +	addq	%r8, %r9
    2.45 +	movq	PTR(PA_PUD_0)(%rsi), %r8
    2.46 +	orq	$PAGE_ATTR, %r8
    2.47 +	movq	%r8, (%r9)
    2.48 +
    2.49 +	shrq	$9, %r10
    2.50 +	sub	$9, %cl
    2.51 +
    2.52 +	movq	%r11, %r9
    2.53 +	andq	%r10, %r9
    2.54 +	shrq	%cl, %r9
    2.55 +
    2.56 +	movq	PTR(VA_PUD_0)(%rsi), %r8
    2.57 +	addq	%r8, %r9
    2.58 +	movq	PTR(PA_PMD_0)(%rsi), %r8
    2.59 +	orq	$PAGE_ATTR, %r8
    2.60 +	movq	%r8, (%r9)
    2.61 +
    2.62 +	shrq	$9, %r10
    2.63 +	sub	$9, %cl
    2.64 +
    2.65 +	movq	%r11, %r9
    2.66 +	andq	%r10, %r9
    2.67 +	shrq	%cl, %r9
    2.68 +
    2.69 +	movq	PTR(VA_PMD_0)(%rsi), %r8
    2.70 +	addq	%r8, %r9
    2.71 +	movq	PTR(PA_PTE_0)(%rsi), %r8
    2.72 +	orq	$PAGE_ATTR, %r8
    2.73 +	movq	%r8, (%r9)
    2.74 +
    2.75 +	shrq	$9, %r10
    2.76 +	sub	$9, %cl
    2.77 +
    2.78 +	movq	%r11, %r9
    2.79 +	andq	%r10, %r9
    2.80 +	shrq	%cl, %r9
    2.81 +
    2.82 +	movq	PTR(VA_PTE_0)(%rsi), %r8
    2.83 +	addq	%r8, %r9
    2.84 +	movq	PTR(PA_CONTROL_PAGE)(%rsi), %r8
    2.85 +	orq	$PAGE_ATTR, %r8
    2.86 +	movq	%r8, (%r9)
    2.87 +
    2.88 +	/* identity map the control page at its physical address */
    2.89 +
    2.90 +	movq	$0x0000ff8000000000, %r10        /* mask */
    2.91 +	mov	$(39 - 3), %cl                   /* bits to shift */
    2.92 +	movq	PTR(PA_CONTROL_PAGE)(%rsi), %r11 /* address to map */
    2.93 +
    2.94 +	movq	%r11, %r9
    2.95 +	andq	%r10, %r9
    2.96 +	shrq	%cl, %r9
    2.97 +
    2.98 +	movq	PTR(VA_PGD)(%rsi), %r8
    2.99 +	addq	%r8, %r9
   2.100 +	movq	PTR(PA_PUD_1)(%rsi), %r8
   2.101 +	orq	$PAGE_ATTR, %r8
   2.102 +	movq	%r8, (%r9)
   2.103 +
   2.104 +	shrq	$9, %r10
   2.105 +	sub	$9, %cl
   2.106 +
   2.107 +	movq	%r11, %r9
   2.108 +	andq	%r10, %r9
   2.109 +	shrq	%cl, %r9
   2.110 +
   2.111 +	movq	PTR(VA_PUD_1)(%rsi), %r8
   2.112 +	addq	%r8, %r9
   2.113 +	movq	PTR(PA_PMD_1)(%rsi), %r8
   2.114 +	orq	$PAGE_ATTR, %r8
   2.115 +	movq	%r8, (%r9)
   2.116 +
   2.117 +	shrq	$9, %r10
   2.118 +	sub	$9, %cl
   2.119 +
   2.120 +	movq	%r11, %r9
   2.121 +	andq	%r10, %r9
   2.122 +	shrq	%cl, %r9
   2.123 +
   2.124 +	movq	PTR(VA_PMD_1)(%rsi), %r8
   2.125 +	addq	%r8, %r9
   2.126 +	movq	PTR(PA_PTE_1)(%rsi), %r8
   2.127 +	orq	$PAGE_ATTR, %r8
   2.128 +	movq	%r8, (%r9)
   2.129 +
   2.130 +	shrq	$9, %r10
   2.131 +	sub	$9, %cl
   2.132 +
   2.133 +	movq	%r11, %r9
   2.134 +	andq	%r10, %r9
   2.135 +	shrq	%cl, %r9
   2.136 +
   2.137 +	movq	PTR(VA_PTE_1)(%rsi), %r8
   2.138 +	addq	%r8, %r9
   2.139 +	movq	PTR(PA_CONTROL_PAGE)(%rsi), %r8
   2.140 +	orq	$PAGE_ATTR, %r8
   2.141 +	movq	%r8, (%r9)
   2.142 +
   2.143  relocate_new_kernel:
   2.144 -	/* %rdi page_list
   2.145 -	 * %rsi reboot_code_buffer
   2.146 +	/* %rdi indirection_page
   2.147 +	 * %rsi page_list
   2.148  	 * %rdx start address
   2.149 -	 * %rcx page_table
   2.150 -	 * %r8  arg5
   2.151 -	 * %r9  arg6
   2.152  	 */
   2.153  
   2.154  	/* zero out flags, and disable interrupts */
   2.155  	pushq $0
   2.156  	popfq
   2.157  
   2.158 -	/* set a new stack at the bottom of our page... */
   2.159 -	lea   4096(%rsi), %rsp
   2.160 +	/* get physical address of control page now */
   2.161 +	/* this is impossible after page table switch */
   2.162 +	movq	PTR(PA_CONTROL_PAGE)(%rsi), %r8
   2.163  
   2.164 -	/* store the parameters back on the stack */
   2.165 -	pushq	%rdx /* store the start address */
   2.166 +	/* get physical address of page table now too */
   2.167 +	movq	PTR(PA_TABLE_PAGE)(%rsi), %rcx
   2.168 +
   2.169 +	/* switch to new set of page tables */
   2.170 +	movq	PTR(PA_PGD)(%rsi), %r9
   2.171 +	movq	%r9, %cr3
   2.172 +
   2.173 +	/* setup a new stack at the end of the physical control page */
   2.174 +	lea	4096(%r8), %rsp
   2.175 +
   2.176 +	/* jump to identity mapped page */
   2.177 +	addq	$(identity_mapped - relocate_kernel), %r8
   2.178 +	pushq	%r8
   2.179 +	ret
   2.180 +
   2.181 +identity_mapped:
   2.182 +	/* store the start address on the stack */
   2.183 +	pushq   %rdx
   2.184  
   2.185  	/* Set cr0 to a known state:
   2.186  	 * 31 1 == Paging enabled
   2.187 @@ -136,8 +274,3 @@ 3:
   2.188  	xorq	%r15, %r15
   2.189  
   2.190  	ret
   2.191 -relocate_new_kernel_end:
   2.192 -
   2.193 -	.globl relocate_new_kernel_size
   2.194 -relocate_new_kernel_size:
   2.195 -	.quad relocate_new_kernel_end - relocate_new_kernel
     3.1 --- a/include/asm-x86_64/kexec.h	Mon Jun 04 10:05:23 2007 +0100
     3.2 +++ b/include/asm-x86_64/kexec.h	Mon Jun 04 10:05:23 2007 +0100
     3.3 @@ -1,6 +1,27 @@
     3.4  #ifndef _X86_64_KEXEC_H
     3.5  #define _X86_64_KEXEC_H
     3.6  
     3.7 +#define PA_CONTROL_PAGE  0
     3.8 +#define VA_CONTROL_PAGE  1
     3.9 +#define PA_PGD           2
    3.10 +#define VA_PGD           3
    3.11 +#define PA_PUD_0         4
    3.12 +#define VA_PUD_0         5
    3.13 +#define PA_PMD_0         6
    3.14 +#define VA_PMD_0         7
    3.15 +#define PA_PTE_0         8
    3.16 +#define VA_PTE_0         9
    3.17 +#define PA_PUD_1         10
    3.18 +#define VA_PUD_1         11
    3.19 +#define PA_PMD_1         12
    3.20 +#define VA_PMD_1         13
    3.21 +#define PA_PTE_1         14
    3.22 +#define VA_PTE_1         15
    3.23 +#define PA_TABLE_PAGE    16
    3.24 +#define PAGES_NR         17
    3.25 +
    3.26 +#ifndef __ASSEMBLY__
    3.27 +
    3.28  #include <linux/string.h>
    3.29  
    3.30  #include <asm/page.h>
    3.31 @@ -64,4 +85,12 @@ static inline void crash_setup_regs(stru
    3.32  		newregs->rip = (unsigned long)current_text_addr();
    3.33  	}
    3.34  }
    3.35 +
    3.36 +NORET_TYPE void
    3.37 +relocate_kernel(unsigned long indirection_page,
    3.38 +		unsigned long page_list,
    3.39 +		unsigned long start_address) ATTRIB_NORET;
    3.40 +
    3.41 +#endif /* __ASSEMBLY__ */
    3.42 +
    3.43  #endif /* _X86_64_KEXEC_H */