mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
[XEN] kexec: add compatability shim for kexec in 32on64 mode.
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
This commit is contained in:
1 parent
9c47bd3d1e
commit
cc1b02ddd4
3 files changed
+168
-7
No files matched your search
@@ -21,7 +21,7 @@
|
||||
|
||||
typedef void (*relocate_new_kernel_t)(
|
||||
unsigned long indirection_page,
|
||||
unsigned long page_list,
|
||||
unsigned long *page_list,
|
||||
unsigned long start_address);
|
||||
|
||||
int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
|
||||
@@ -44,8 +44,26 @@ int machine_kexec_load(int type, int slot, xen_kexec_image_t *image)
|
||||
else
|
||||
{
|
||||
/* Odd pages: va for previous ma. */
|
||||
set_fixmap(fix_base + (k >> 1), prev_ma);
|
||||
image->page_list[k] = fix_to_virt(fix_base + (k >> 1));
|
||||
if ( IS_COMPAT(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,11 +118,27 @@ void machine_reboot_kexec(xen_kexec_image_t *image)
|
||||
|
||||
void machine_kexec(xen_kexec_image_t *image)
|
||||
{
|
||||
relocate_new_kernel_t rnk;
|
||||
#ifdef CONFIG_COMPAT
|
||||
if ( IS_COMPAT(dom0) )
|
||||
{
|
||||
extern void compat_machine_kexec(unsigned long rnk,
|
||||
unsigned long indirection_page,
|
||||
unsigned long *page_list,
|
||||
unsigned long start_address);
|
||||
compat_machine_kexec(image->page_list[1],
|
||||
image->indirection_page,
|
||||
image->page_list,
|
||||
image->start_address);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
relocate_new_kernel_t rnk;
|
||||
|
||||
rnk = (relocate_new_kernel_t) image->page_list[1];
|
||||
(*rnk)(image->indirection_page, (unsigned long)image->page_list,
|
||||
image->start_address);
|
||||
rnk = (relocate_new_kernel_t) image->page_list[1];
|
||||
(*rnk)(image->indirection_page, image->page_list,
|
||||
image->start_address);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
obj-y += entry.o
|
||||
obj-y += compat_kexec.o
|
||||
obj-y += gpr_switch.o
|
||||
obj-y += mm.o
|
||||
obj-y += traps.o
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Compatibility kexec handler.
|
||||
*/
|
||||
|
||||
#include <xen/config.h>
|
||||
|
||||
#include <asm/asm_defns.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
.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
|
||||
|
||||
movq %rbx,%rdx
|
||||
mov $__PAGE_OFFSET,%rbx
|
||||
sub %rbx, %rdx
|
||||
|
||||
/*
|
||||
* Setup an identity mapped region in PML4[0] of idle page
|
||||
* table.
|
||||
*/
|
||||
lea idle_pg_table_l3(%rip),%rax
|
||||
sub %rbx,%rax
|
||||
or $0x63,%rax
|
||||
mov %rax, idle_pg_table(%rip)
|
||||
|
||||
/* Switch to idle page table. */
|
||||
movq $(idle_pg_table - __PAGE_OFFSET), %rax
|
||||
movq %rax, %cr3
|
||||
|
||||
/* Jump to low identity mapping in compatibility mode. */
|
||||
ljmp *compatibility_mode_far(%rip)
|
||||
ud2
|
||||
|
||||
compatibility_mode_far:
|
||||
.long compatibility_mode - __PAGE_OFFSET
|
||||
.long __HYPERVISOR_CS32
|
||||
|
||||
.code32
|
||||
|
||||
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 $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. */
|
||||
movl $compat_pg_table - __PAGE_OFFSET, %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
|
||||
|
||||
popl %eax
|
||||
call *%eax
|
||||
ud2
|
||||
|
||||
compat_page_list:
|
||||
.fill 12,4,0
|
||||
|
||||
.align 32,0
|
||||
|
||||
/*
|
||||
* These compat page tables contain an identity mapping of the
|
||||
* first 1G of the physical address space.
|
||||
*/
|
||||
compat_pg_table:
|
||||
.long compat_pg_table_l2 + 0*PAGE_SIZE + 0x01 - __PAGE_OFFSET, 0
|
||||
.long 0, 0
|
||||
.long 0, 0
|
||||
.long 0, 0
|
||||
|
||||
.align 4096,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
|
||||