ia64/linux-2.6.18-xen.hg

changeset 2:07baeb6664de

Imported patch git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.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 95e4a4dfb668
children 948d16bbacc2
files arch/i386/kernel/machine_kexec.c arch/i386/kernel/relocate_kernel.S include/asm-i386/kexec.h
line diff
     1.1 --- a/arch/i386/kernel/machine_kexec.c	Mon May 21 14:14:36 2007 +0100
     1.2 +++ b/arch/i386/kernel/machine_kexec.c	Mon Jun 04 10:05:23 2007 +0100
     1.3 @@ -20,70 +20,13 @@
     1.4  #include <asm/system.h>
     1.5  
     1.6  #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
     1.7 -
     1.8 -#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
     1.9 -#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
    1.10 -#define L2_ATTR (_PAGE_PRESENT)
    1.11 -
    1.12 -#define LEVEL0_SIZE (1UL << 12UL)
    1.13 -
    1.14 -#ifndef CONFIG_X86_PAE
    1.15 -#define LEVEL1_SIZE (1UL << 22UL)
    1.16 -static u32 pgtable_level1[1024] PAGE_ALIGNED;
    1.17 -
    1.18 -static void identity_map_page(unsigned long address)
    1.19 -{
    1.20 -	unsigned long level1_index, level2_index;
    1.21 -	u32 *pgtable_level2;
    1.22 -
    1.23 -	/* Find the current page table */
    1.24 -	pgtable_level2 = __va(read_cr3());
    1.25 -
    1.26 -	/* Find the indexes of the physical address to identity map */
    1.27 -	level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
    1.28 -	level2_index = address / LEVEL1_SIZE;
    1.29 -
    1.30 -	/* Identity map the page table entry */
    1.31 -	pgtable_level1[level1_index] = address | L0_ATTR;
    1.32 -	pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
    1.33 -
    1.34 -	/* Flush the tlb so the new mapping takes effect.
    1.35 -	 * Global tlb entries are not flushed but that is not an issue.
    1.36 -	 */
    1.37 -	load_cr3(pgtable_level2);
    1.38 -}
    1.39 -
    1.40 -#else
    1.41 -#define LEVEL1_SIZE (1UL << 21UL)
    1.42 -#define LEVEL2_SIZE (1UL << 30UL)
    1.43 -static u64 pgtable_level1[512] PAGE_ALIGNED;
    1.44 -static u64 pgtable_level2[512] PAGE_ALIGNED;
    1.45 -
    1.46 -static void identity_map_page(unsigned long address)
    1.47 -{
    1.48 -	unsigned long level1_index, level2_index, level3_index;
    1.49 -	u64 *pgtable_level3;
    1.50 -
    1.51 -	/* Find the current page table */
    1.52 -	pgtable_level3 = __va(read_cr3());
    1.53 -
    1.54 -	/* Find the indexes of the physical address to identity map */
    1.55 -	level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
    1.56 -	level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE;
    1.57 -	level3_index = address / LEVEL2_SIZE;
    1.58 -
    1.59 -	/* Identity map the page table entry */
    1.60 -	pgtable_level1[level1_index] = address | L0_ATTR;
    1.61 -	pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
    1.62 -	set_64bit(&pgtable_level3[level3_index],
    1.63 -					       __pa(pgtable_level2) | L2_ATTR);
    1.64 -
    1.65 -	/* Flush the tlb so the new mapping takes effect.
    1.66 -	 * Global tlb entries are not flushed but that is not an issue.
    1.67 -	 */
    1.68 -	load_cr3(pgtable_level3);
    1.69 -}
    1.70 +static u32 kexec_pgd[1024] PAGE_ALIGNED;
    1.71 +#ifdef CONFIG_X86_PAE
    1.72 +static u32 kexec_pmd0[1024] PAGE_ALIGNED;
    1.73 +static u32 kexec_pmd1[1024] PAGE_ALIGNED;
    1.74  #endif
    1.75 +static u32 kexec_pte0[1024] PAGE_ALIGNED;
    1.76 +static u32 kexec_pte1[1024] PAGE_ALIGNED;
    1.77  
    1.78  static void set_idt(void *newidt, __u16 limit)
    1.79  {
    1.80 @@ -127,16 +70,6 @@ static void load_segments(void)
    1.81  #undef __STR
    1.82  }
    1.83  
    1.84 -typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
    1.85 -					unsigned long indirection_page,
    1.86 -					unsigned long reboot_code_buffer,
    1.87 -					unsigned long start_address,
    1.88 -					unsigned int has_pae) ATTRIB_NORET;
    1.89 -
    1.90 -extern const unsigned char relocate_new_kernel[];
    1.91 -extern void relocate_new_kernel_end(void);
    1.92 -extern const unsigned int relocate_new_kernel_size;
    1.93 -
    1.94  /*
    1.95   * A architecture hook called to validate the
    1.96   * proposed image and prepare the control pages
    1.97 @@ -169,25 +102,29 @@ void machine_kexec_cleanup(struct kimage
    1.98   */
    1.99  NORET_TYPE void machine_kexec(struct kimage *image)
   1.100  {
   1.101 -	unsigned long page_list;
   1.102 -	unsigned long reboot_code_buffer;
   1.103 -
   1.104 -	relocate_new_kernel_t rnk;
   1.105 +	unsigned long page_list[PAGES_NR];
   1.106 +	void *control_page;
   1.107  
   1.108  	/* Interrupts aren't acceptable while we reboot */
   1.109  	local_irq_disable();
   1.110  
   1.111 -	/* Compute some offsets */
   1.112 -	reboot_code_buffer = page_to_pfn(image->control_code_page)
   1.113 -								<< PAGE_SHIFT;
   1.114 -	page_list = image->head;
   1.115 +	control_page = page_address(image->control_code_page);
   1.116 +	memcpy(control_page, relocate_kernel, PAGE_SIZE);
   1.117  
   1.118 -	/* Set up an identity mapping for the reboot_code_buffer */
   1.119 -	identity_map_page(reboot_code_buffer);
   1.120 -
   1.121 -	/* copy it out */
   1.122 -	memcpy((void *)reboot_code_buffer, relocate_new_kernel,
   1.123 -						relocate_new_kernel_size);
   1.124 +	page_list[PA_CONTROL_PAGE] = __pa(control_page);
   1.125 +	page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
   1.126 +	page_list[PA_PGD] = __pa(kexec_pgd);
   1.127 +	page_list[VA_PGD] = (unsigned long)kexec_pgd;
   1.128 +#ifdef CONFIG_X86_PAE
   1.129 +	page_list[PA_PMD_0] = __pa(kexec_pmd0);
   1.130 +	page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
   1.131 +	page_list[PA_PMD_1] = __pa(kexec_pmd1);
   1.132 +	page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
   1.133 +#endif
   1.134 +	page_list[PA_PTE_0] = __pa(kexec_pte0);
   1.135 +	page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
   1.136 +	page_list[PA_PTE_1] = __pa(kexec_pte1);
   1.137 +	page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
   1.138  
   1.139  	/* The segment registers are funny things, they have both a
   1.140  	 * visible and an invisible part.  Whenever the visible part is
   1.141 @@ -206,6 +143,6 @@ NORET_TYPE void machine_kexec(struct kim
   1.142  	set_idt(phys_to_virt(0),0);
   1.143  
   1.144  	/* now call it */
   1.145 -	rnk = (relocate_new_kernel_t) reboot_code_buffer;
   1.146 -	(*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
   1.147 +	relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
   1.148 +			image->start, cpu_has_pae);
   1.149  }
     2.1 --- a/arch/i386/kernel/relocate_kernel.S	Mon May 21 14:14:36 2007 +0100
     2.2 +++ b/arch/i386/kernel/relocate_kernel.S	Mon Jun 04 10:05:23 2007 +0100
     2.3 @@ -7,16 +7,138 @@
     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 << 2)
    2.20 +#define PAGE_ALIGNED (1 << PAGE_SHIFT)
    2.21 +#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
    2.22 +#define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */
    2.23 +
    2.24 +	.text
    2.25 +	.align PAGE_ALIGNED
    2.26 +	.globl relocate_kernel
    2.27 +relocate_kernel:
    2.28 +	movl	8(%esp), %ebp /* list of pages */
    2.29 +
    2.30 +#ifdef CONFIG_X86_PAE
    2.31 +	/* map the control page at its virtual address */
    2.32 +
    2.33 +	movl	PTR(VA_PGD)(%ebp), %edi
    2.34 +	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
    2.35 +	andl	$0xc0000000, %eax
    2.36 +	shrl	$27, %eax
    2.37 +	addl	%edi, %eax
    2.38 +
    2.39 +	movl	PTR(PA_PMD_0)(%ebp), %edx
    2.40 +	orl	$PAE_PGD_ATTR, %edx
    2.41 +	movl	%edx, (%eax)
    2.42 +
    2.43 +	movl	PTR(VA_PMD_0)(%ebp), %edi
    2.44 +	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
    2.45 +	andl	$0x3fe00000, %eax
    2.46 +	shrl	$18, %eax
    2.47 +	addl	%edi, %eax
    2.48 +
    2.49 +	movl	PTR(PA_PTE_0)(%ebp), %edx
    2.50 +	orl	$PAGE_ATTR, %edx
    2.51 +	movl	%edx, (%eax)
    2.52 +
    2.53 +	movl	PTR(VA_PTE_0)(%ebp), %edi
    2.54 +	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
    2.55 +	andl	$0x001ff000, %eax
    2.56 +	shrl	$9, %eax
    2.57 +	addl	%edi, %eax
    2.58 +
    2.59 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
    2.60 +	orl	$PAGE_ATTR, %edx
    2.61 +	movl	%edx, (%eax)
    2.62 +
    2.63 +	/* identity map the control page at its physical address */
    2.64 +
    2.65 +	movl	PTR(VA_PGD)(%ebp), %edi
    2.66 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
    2.67 +	andl	$0xc0000000, %eax
    2.68 +	shrl	$27, %eax
    2.69 +	addl	%edi, %eax
    2.70 +
    2.71 +	movl	PTR(PA_PMD_1)(%ebp), %edx
    2.72 +	orl	$PAE_PGD_ATTR, %edx
    2.73 +	movl	%edx, (%eax)
    2.74 +
    2.75 +	movl	PTR(VA_PMD_1)(%ebp), %edi
    2.76 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
    2.77 +	andl	$0x3fe00000, %eax
    2.78 +	shrl	$18, %eax
    2.79 +	addl	%edi, %eax
    2.80 +
    2.81 +	movl	PTR(PA_PTE_1)(%ebp), %edx
    2.82 +	orl	$PAGE_ATTR, %edx
    2.83 +	movl	%edx, (%eax)
    2.84 +
    2.85 +	movl	PTR(VA_PTE_1)(%ebp), %edi
    2.86 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
    2.87 +	andl	$0x001ff000, %eax
    2.88 +	shrl	$9, %eax
    2.89 +	addl	%edi, %eax
    2.90 +
    2.91 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
    2.92 +	orl	$PAGE_ATTR, %edx
    2.93 +	movl	%edx, (%eax)
    2.94 +#else
    2.95 +	/* map the control page at its virtual address */
    2.96 +
    2.97 +	movl	PTR(VA_PGD)(%ebp), %edi
    2.98 +	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
    2.99 +	andl	$0xffc00000, %eax
   2.100 +	shrl	$20, %eax
   2.101 +	addl	%edi, %eax
   2.102 +
   2.103 +	movl	PTR(PA_PTE_0)(%ebp), %edx
   2.104 +	orl	$PAGE_ATTR, %edx
   2.105 +	movl	%edx, (%eax)
   2.106 +
   2.107 +	movl	PTR(VA_PTE_0)(%ebp), %edi
   2.108 +	movl	PTR(VA_CONTROL_PAGE)(%ebp), %eax
   2.109 +	andl	$0x003ff000, %eax
   2.110 +	shrl	$10, %eax
   2.111 +	addl	%edi, %eax
   2.112 +
   2.113 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
   2.114 +	orl	$PAGE_ATTR, %edx
   2.115 +	movl	%edx, (%eax)
   2.116 +
   2.117 +	/* identity map the control page at its physical address */
   2.118 +
   2.119 +	movl	PTR(VA_PGD)(%ebp), %edi
   2.120 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
   2.121 +	andl	$0xffc00000, %eax
   2.122 +	shrl	$20, %eax
   2.123 +	addl	%edi, %eax
   2.124 +
   2.125 +	movl	PTR(PA_PTE_1)(%ebp), %edx
   2.126 +	orl	$PAGE_ATTR, %edx
   2.127 +	movl	%edx, (%eax)
   2.128 +
   2.129 +	movl	PTR(VA_PTE_1)(%ebp), %edi
   2.130 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %eax
   2.131 +	andl	$0x003ff000, %eax
   2.132 +	shrl	$10, %eax
   2.133 +	addl	%edi, %eax
   2.134 +
   2.135 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edx
   2.136 +	orl	$PAGE_ATTR, %edx
   2.137 +	movl	%edx, (%eax)
   2.138 +#endif
   2.139 +
   2.140  relocate_new_kernel:
   2.141  	/* read the arguments and say goodbye to the stack */
   2.142  	movl  4(%esp), %ebx /* page_list */
   2.143 -	movl  8(%esp), %ebp /* reboot_code_buffer */
   2.144 +	movl  8(%esp), %ebp /* list of pages */
   2.145  	movl  12(%esp), %edx /* start address */
   2.146  	movl  16(%esp), %ecx /* cpu_has_pae */
   2.147  
   2.148 @@ -24,11 +146,26 @@ relocate_new_kernel:
   2.149  	pushl $0
   2.150  	popfl
   2.151  
   2.152 -	/* set a new stack at the bottom of our page... */
   2.153 -	lea   4096(%ebp), %esp
   2.154 +	/* get physical address of control page now */
   2.155 +	/* this is impossible after page table switch */
   2.156 +	movl	PTR(PA_CONTROL_PAGE)(%ebp), %edi
   2.157  
   2.158 -	/* store the parameters back on the stack */
   2.159 -	pushl   %edx /* store the start address */
   2.160 +	/* switch to new set of page tables */
   2.161 +	movl	PTR(PA_PGD)(%ebp), %eax
   2.162 +	movl	%eax, %cr3
   2.163 +
   2.164 +	/* setup a new stack at the end of the physical control page */
   2.165 +	lea	4096(%edi), %esp
   2.166 +
   2.167 +	/* jump to identity mapped page */
   2.168 +	movl    %edi, %eax
   2.169 +	addl    $(identity_mapped - relocate_kernel), %eax
   2.170 +	pushl   %eax
   2.171 +	ret
   2.172 +
   2.173 +identity_mapped:
   2.174 +	/* store the start address on the stack */
   2.175 +	pushl   %edx
   2.176  
   2.177  	/* Set cr0 to a known state:
   2.178  	 * 31 0 == Paging disabled
   2.179 @@ -113,8 +250,3 @@ 3:
   2.180  	xorl    %edi, %edi
   2.181  	xorl    %ebp, %ebp
   2.182  	ret
   2.183 -relocate_new_kernel_end:
   2.184 -
   2.185 -	.globl relocate_new_kernel_size
   2.186 -relocate_new_kernel_size:
   2.187 -	.long relocate_new_kernel_end - relocate_new_kernel
     3.1 --- a/include/asm-i386/kexec.h	Mon May 21 14:14:36 2007 +0100
     3.2 +++ b/include/asm-i386/kexec.h	Mon Jun 04 10:05:23 2007 +0100
     3.3 @@ -1,6 +1,26 @@
     3.4  #ifndef _I386_KEXEC_H
     3.5  #define _I386_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_PTE_0         4
    3.12 +#define VA_PTE_0         5
    3.13 +#define PA_PTE_1         6
    3.14 +#define VA_PTE_1         7
    3.15 +#ifdef CONFIG_X86_PAE
    3.16 +#define PA_PMD_0         8
    3.17 +#define VA_PMD_0         9
    3.18 +#define PA_PMD_1         10
    3.19 +#define VA_PMD_1         11
    3.20 +#define PAGES_NR         12
    3.21 +#else
    3.22 +#define PAGES_NR         8
    3.23 +#endif
    3.24 +
    3.25 +#ifndef __ASSEMBLY__
    3.26 +
    3.27  #include <asm/fixmap.h>
    3.28  #include <asm/ptrace.h>
    3.29  #include <asm/string.h>
    3.30 @@ -72,5 +92,12 @@ static inline void crash_setup_regs(stru
    3.31                 newregs->eip = (unsigned long)current_text_addr();
    3.32         }
    3.33  }
    3.34 +asmlinkage NORET_TYPE void
    3.35 +relocate_kernel(unsigned long indirection_page,
    3.36 +		unsigned long control_page,
    3.37 +		unsigned long start_address,
    3.38 +		unsigned int has_pae) ATTRIB_NORET;
    3.39 +
    3.40 +#endif /* __ASSEMBLY__ */
    3.41  
    3.42  #endif /* _I386_KEXEC_H */