summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-11-19 08:56:22 -0800
committerSimon Horman <horms@verge.net.au>2012-11-21 09:15:59 +0900
commitb4f9f8599679259a471f3430f11966c6db78ad3d (patch)
treebe9bf0f8d71432d974956e829ad4abfb1fbe61bb
parent53e81b4ad85ef2b3326a15d54a07e481c44ed17b (diff)
downloadkexec-tools-b4f9f8599679259a471f3430f11966c6db78ad3d.tar.gz
kexec x86_64: Make purgatory relocatable anywhere in the 64bit address space.
Remove kexec/arch/i386/compat_x6_64.S purgatory/arch/i386/linux-entry16.S and purgatory/arch/i386/entry16.S Those were early attempts at entry32-16.S that should have been deleted long ago. Strip the purgatory code of debug symbols. There is no need to carry debug symbols we will never use around in /sbin/kexec. On x86_64 use -mcmodel=large so that the code is built without any 32bit assumptions. -mcmodel=medium and -mcmodel=small result int code that has 32bit relocations against variables that can live anywhere in the address space Modify the assembly in entry64.S and setup-x86_64.S to use %rip relative addressing of variables so no relocates are emitted. Modify entry64-32.S so that it does not have any relocations that can not be processed when purgatory is loaded above 4G. entry64-32.S jumps to a 32bit entry point and can not itself be used above 4G so these changes merely prevent it from being a problem in the other case. eip is modifed to be a 64bit value of which only the low 32bits are exported outside of entry64-32.S The long mode exit code is modified to run with a %cs value whose base address is the address of the symbol entry32. From there all of the 32bit code in entry64-32.S can read variables by reading them through %cs. Until the final jump to the the target address which is made a far jump reloading %cs and the intstruction pointer. Modify entry32-16.S and entry32-16-debug.S to be position independent 32bit code. At their start make a short call to push the current value of %eip on the stack and pop it off. Allowing the calculation of the address of entry16 which the code has always kept in %ebx. Update the pointer to the gdt in the gdt so that lgdt will work. Modify the instructions in entry32-16.S and entry32-16-debug.S so that the 32bit code uses offsets from %ebx which points at entry16. Tested-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r--kexec/arch/i386/compat_x86_64.S131
-rw-r--r--purgatory/Makefile1
-rw-r--r--purgatory/arch/i386/entry16.S160
-rw-r--r--purgatory/arch/i386/entry32-16-debug.S25
-rw-r--r--purgatory/arch/i386/entry32-16.S25
-rw-r--r--purgatory/arch/i386/linux-entry16.S623
-rw-r--r--purgatory/arch/x86_64/Makefile4
-rw-r--r--purgatory/arch/x86_64/entry64-32.S68
-rw-r--r--purgatory/arch/x86_64/entry64.S5
-rw-r--r--purgatory/arch/x86_64/setup-x86_64.S4
10 files changed, 88 insertions, 958 deletions
diff --git a/kexec/arch/i386/compat_x86_64.S b/kexec/arch/i386/compat_x86_64.S
deleted file mode 100644
index f8a04e93..00000000
--- a/kexec/arch/i386/compat_x86_64.S
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * kexec: Linux boots Linux
- *
- * Copyright (C) 2003,2004,2005 Eric Biederman (ebiederm@xmission.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation (version 2 of the License).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#define USE_LRET 0
-
-.data
- .equ MSR_K6_EFER, 0xC0000080
- .equ EFER_LME, 0x00000100
- .equ X86_CR4_PAE, 0x00000020
- .equ CR0_PG, 0x80000000
-
- .globl compat_x86_64, compat_x86_64_size, compat_x86_64_entry32
- .code64
- .balign 16
-compat_x86_64:
- /* Compute where I am running at */
- leaq compat_x86_64(%rip), %rbx
-
- /* Relocate the code */
- addq %rbx, gdt_addr(%rip)
-#if !USE_LRET
- addl %ebx, lm_exit_addr(%rip)
-#endif
-
- /* Lookup the 32bit start address */
- movl compat_x86_64_entry32(%rip), %ebx
- pushq %rbx
-
-#if USE_LRET
- /* Push the 64bit start address */
- pushq $0x10
- pushq lm_exit(%rip)
-#endif
-
- /* This also acts as a serializing instruction ensuring
- * my self modifying code works.
- */
- lgdt gdt(%rip)
-
-#if USE_LRET
- lret
-#else
- /* Switch to 32bit compatiblity mode */
- ljmp *lm_exit_addr(%rip)
-#endif
-lm_exit:
- .code32
-
- /* Disable paging */
- movl %cr0, %eax
- andl $~CR0_PG, %eax
- movl %eax, %cr0
-
- /* Disable long mode */
- movl $MSR_K6_EFER, %ecx
- rdmsr
- andl $~EFER_LME, %eax
- wrmsr
-
- /* Disable PAE */
- xorl %eax, %eax
- movl %eax, %cr4
-
- /* load the data segments */
- movl $0x18, %eax /* data segment */
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- movl %eax, %fs
- movl %eax, %gs
-
- /* Remove the 32 bits of the 64 bit start address */
- popl %eax
-
- /* set all of the registers to known values */
- /* leave %esp alone */
-
- xorl %eax, %eax
- xorl %ebx, %ebx
- xorl %ecx, %ecx
- xorl %edx, %edx
- xorl %esi, %esi
- xorl %edi, %edi
- xorl %ebp, %ebp
-
- ret
-
- .balign 16
-gdt: /* 0x00 unusable segment
- * 0x08 unused
- * so use them as the gdt ptr
- */
- .word gdt_end - gdt - 1
-gdt_addr:
- .quad gdt - compat_x86_64
- .word 0, 0, 0
-
- /* 0x10 4GB flat code segment */
- .word 0xFFFF, 0x0000, 0x9A00, 0x00CF
- /* 0x18 4GB flat data segment */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-gdt_end:
-
-#if !USE_LRET
-lm_exit_addr:
- .long lm_exit - compat_x86_64
- .long 0x10
-#endif
-
-compat_x86_64_entry32:
- .long 0
-
-compat_x86_64_end:
-compat_x86_64_size:
- .long compat_x86_64_end - compat_x86_64
diff --git a/purgatory/Makefile b/purgatory/Makefile
index ee1679c3..e39adeca 100644
--- a/purgatory/Makefile
+++ b/purgatory/Makefile
@@ -64,6 +64,7 @@ $(PURGATORY): $(PURGATORY_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
# $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB)
+ $(STRIP) --strip-debug $@
echo::
@echo "PURGATORY_SRCS $(PURGATORY_SRCS)"
diff --git a/purgatory/arch/i386/entry16.S b/purgatory/arch/i386/entry16.S
deleted file mode 100644
index c4a3dad8..00000000
--- a/purgatory/arch/i386/entry16.S
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * kexec: Linux boots Linux
- *
- * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation (version 2 of the License).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#undef i386
- .text
- .globl entry16, entry16_regs
- .arch i386
- .balign 16
-entry16:
- .code32
- /* Compute where I am running at */
- movl $entry16, %ebx
-
- /* Fixup my real mode segment */
- movl %ebx, %eax
- shrl $4, %eax
- movw %ax, 2 + realptr
-
- /* Fixup the gdt */
- movl %ebx, %eax
- shll $16, %eax
-
- movl %ebx, %ecx
- shrl $16, %ecx
- andl $0xff, %ecx
-
- movl %ebx, %edx
- andl $0xff000000, %edx
- orl %edx, %ecx
-
- orl %eax, 0x08 + gdt
- orl %ecx, 0x0c + gdt
- orl %eax, 0x10 + gdt
- orl %ecx, 0x14 + gdt
-
-
- /* Setup the classic BIOS interrupt table at 0x0 */
- lidt idtptr
-
- /* Provide us with 16bit segments that we can use */
- lgdt gdt
-
- /* Note we don't disable the a20 line, (this shouldn't be required)
- * The code to do it is in kexec_test and it is a real pain.
- * I will worry about that when I need it.
- */
-
- /* Load 16bit data segments, to ensure the segment limits are set */
- movl $0x10, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- movl %eax, %fs
- movl %eax, %gs
-
- /* switch to 16bit mode */
- ljmp $0x08, $1f - entry16
-1:
- .code16
- /* Disable Paging and protected mode */
- /* clear the PG & PE bits of CR0 */
- movl %cr0,%eax
- andl $~((1 << 31)|(1<<0)),%eax
- movl %eax,%cr0
-
- /* make intersegment jmp to flush the processor pipeline
- * and reload %cs:%eip (to clear upper 16 bits of %eip).
- */
- ljmp *(realptr - entry16)
-3:
- /* we are in real mode now
- * set up the real mode segment registers : %ds, $ss, %es
- */
- /* Setup the data segment */
- movw %cs, %ax
- movw %ax, %ds
-
- /* Load the registers */
- movl eax - entry16, %eax
- movl ebx - entry16, %ebx
- movl ecx - entry16, %ecx
- movl edx - entry16, %edx
- movl esi - entry16, %esi
- movl edi - entry16, %esi
- movl esp - entry16, %esp
- movl ebp - entry16, %ebp
- movw es - entry16, %es
- movw ss - entry16, %ss
- movw fs - entry16, %fs
- movw gs - entry16, %gs
- movw ds - entry16, %ds
-
- /* Jump to the kernel entrypoint */
- ljmp %cs:*(realdest - entry16)
-
- .balign 4
-entry16_regs:
-eax: .long 0x00000000
-ebx: .long 0x00000000
-ecx: .long 0x00000000
-edx: .long 0x00000000
-esi: .long 0x00000000
-edi: .long 0x00000000
-esp: .long 0x00000000
-ebp: .long 0x00000000
-ds: .word 0x0000
-es: .word 0x0000
-ss: .word 0x0000
-fs: .word 0x0000
-gs: .word 0x0000
-realdest:
-ip: .word 0x0000
-cs: .word 0x0000
-pad: .word 0x0000
- .size entry16_regs, . - entry16_regs
-
- .balign 16
-realptr:
- .word 3b - entry16
- .word 0x0000
-
- .data
- .balign 16
-
-idtptr:
- /* 256 entry idt at 0 */
- .word 0x400 - 1
- .word 0, 0
-
- .balign 16
-gdt:
- /* 0x00 unusable segment so used as the gdt ptr */
- .word gdt_end - gdt - 1
- .long gdt
- .word 0
-
- /* 0x08 16 bit real mode code segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x9b, 0x00, 0x00
-
- /* 0x10 16 bit real mode data segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x93, 0x00, 0x00
-gdt_end:
diff --git a/purgatory/arch/i386/entry32-16-debug.S b/purgatory/arch/i386/entry32-16-debug.S
index 82b58cae..5167944d 100644
--- a/purgatory/arch/i386/entry32-16-debug.S
+++ b/purgatory/arch/i386/entry32-16-debug.S
@@ -29,15 +29,20 @@
.balign 16
entry16_debug:
.code32
- /* Compute where I am running at */
- movl $entry16_debug, %ebx
+ /* Compute where I am running at (assumes esp valid) */
+ call 1f
+1: popl %ebx
+ subl $(1b - entry16_debug), %ebx
/* Fixup my real mode segment */
movl %ebx, %eax
shrl $4, %eax
- movw %ax, 2 + realptr
+ movw %ax, (2 + realptr - entry16_debug)(%ebx)
/* Fixup the gdt */
+ leal (gdt - entry16_debug)(%ebx), %eax
+ movl %eax, (0x02 + gdt - entry16_debug)(%ebx)
+
movl %ebx, %eax
shll $16, %eax
@@ -49,19 +54,19 @@ entry16_debug:
andl $0xff000000, %edx
orl %edx, %ecx
- orl %eax, 0x08 + gdt
- orl %ecx, 0x0c + gdt
- orl %eax, 0x10 + gdt
- orl %ecx, 0x14 + gdt
+ orl %eax, (0x08 + gdt - entry16_debug)(%ebx)
+ orl %ecx, (0x0c + gdt - entry16_debug)(%ebx)
+ orl %eax, (0x10 + gdt - entry16_debug)(%ebx)
+ orl %ecx, (0x14 + gdt - entry16_debug)(%ebx)
DEBUG_CHAR('a')
/* Setup the classic BIOS interrupt table at 0x0 */
- lidt idtptr
+ lidt (idtptr - entry16_debug)(%ebx)
DEBUG_CHAR('b')
/* Provide us with 16bit segments that we can use */
- lgdt gdt
+ lgdt (gdt - entry16_debug)(%ebx)
DEBUG_CHAR('c')
/* Note we don't disable the a20 line, (this shouldn't be required)
@@ -160,7 +165,7 @@ idtptr:
gdt:
/* 0x00 unusable segment so used as the gdt ptr */
.word gdt_end - gdt - 1
- .long gdt
+ .long 0 /* gdt */
.word 0
/* 0x08 16 bit real mode code segment */
diff --git a/purgatory/arch/i386/entry32-16.S b/purgatory/arch/i386/entry32-16.S
index aaf1273f..c051aab0 100644
--- a/purgatory/arch/i386/entry32-16.S
+++ b/purgatory/arch/i386/entry32-16.S
@@ -24,15 +24,20 @@
.balign 16
entry16:
.code32
- /* Compute where I am running at */
- movl $entry16, %ebx
+ /* Compute where I am running at (assumes esp valid) */
+ call 1f
+1: popl %ebx
+ subl $(1b - entry16), %ebx
/* Fixup my real mode segment */
movl %ebx, %eax
shrl $4, %eax
- movw %ax, 2 + realptr
+ movw %ax, (2 + realptr - entry16)(%ebx)
/* Fixup the gdt */
+ leal (gdt - entry16)(%ebx), %eax
+ movl %eax, (0x02 + gdt - entry16)(%ebx)
+
movl %ebx, %eax
shll $16, %eax
@@ -44,17 +49,17 @@ entry16:
andl $0xff000000, %edx
orl %edx, %ecx
- orl %eax, 0x08 + gdt
- orl %ecx, 0x0c + gdt
- orl %eax, 0x10 + gdt
- orl %ecx, 0x14 + gdt
+ orl %eax, (0x08 + gdt - entry16)(%ebx)
+ orl %ecx, (0x0c + gdt - entry16)(%ebx)
+ orl %eax, (0x10 + gdt - entry16)(%ebx)
+ orl %ecx, (0x14 + gdt - entry16)(%ebx)
/* Setup the classic BIOS interrupt table at 0x0 */
- lidt idtptr
+ lidt (idtptr - entry16)(%ebx)
/* Provide us with 16bit segments that we can use */
- lgdt gdt
+ lgdt (gdt - entry16)(%ebx)
/* Note we don't disable the a20 line, (this shouldn't be required)
* The code to do it is in kexec_test and it is a real pain.
@@ -147,7 +152,7 @@ idtptr:
gdt:
/* 0x00 unusable segment so used as the gdt ptr */
.word gdt_end - gdt - 1
- .long gdt
+ .long 0 /* gdt */
.word 0
/* 0x08 16 bit real mode code segment */
diff --git a/purgatory/arch/i386/linux-entry16.S b/purgatory/arch/i386/linux-entry16.S
deleted file mode 100644
index 7ab0b2a3..00000000
--- a/purgatory/arch/i386/linux-entry16.S
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * kexec: Linux boots Linux
- *
- * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation (version 2 of the License).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#if 1
-#define TTYS0_BASE 0x3f8
-#define TTYS0_RBR (TTYS0_BASE+0x00)
-#define TTYS0_TBR TTYS0_RBR
-#define TTYS0_LSR (TTYS0_BASE+0x05)
-
-
- /* uses: ax, dx */
-#define TTYS0_TX_AL \
- mov %al, %ah ; \
-9: mov $TTYS0_LSR, %dx ; \
- inb %dx, %al ; \
- test $0x20, %al ; \
- je 9b ; \
- mov $TTYS0_TBR, %dx ; \
- mov %ah, %al ; \
- outb %al, %dx ; \
-9: mov $TTYS0_LSR, %dx ; \
- inb %dx, %al ; \
- test $0x40, %al ; \
- jz 9b
-
-
-
- /* uses: ax, dx */
-#define TTYS0_TX_CHAR(byte) \
- mov byte, %al ; \
- TTYS0_TX_AL
-
- /* uses: ax, dx */
-#define TTYS0_TX_HEX32(lword) \
- mov lword, %eax ; \
- shr $28, %eax ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $24, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $20, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $16, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $12, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $8, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $4, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL
-
-
-#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
-#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
-#else
-#define DEBUG_CHAR(x)
-#define DEBUG_TX_HEX32(x)
-#endif
-
-#undef i386
- .text
- .globl entry16, entry16_regs
- .arch i386
- .balign 16
-entry16:
- .code32
-
-DEBUG_CHAR('a')
- /* Setup the classic BIOS interrupt table at 0x0 */
- lidt idtptr
-
-DEBUG_CHAR('b')
- /* Provide us with 16bit segments that we can use */
- lgdt gdt
-
-DEBUG_CHAR('c')
- /* Note we don't disable the a20 line, (this shouldn't be required)
- * The code to do it is in kexec_test and it is a real pain.
- * I will worry about that when I need it.
- */
-
- /* Load 16bit data segments, to ensure the segment limits are set */
- movl $0x10, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- movl %eax, %fs
- movl %eax, %gs
-
-DEBUG_CHAR('d')
-
- /* switch to 16bit mode */
- ljmp $0x08, $1f - entry16
-1:
- .code16
-DEBUG_CHAR('e')
- /* Disable Paging and protected mode */
- /* clear the PG & PE bits of CR0 */
- movl %cr0,%eax
- andl $~((1 << 31)|(1<<0)),%eax
- movl %eax,%cr0
-
-DEBUG_CHAR('f')
- /* make intersegment jmp to flush the processor pipeline
- * and reload %cs:%eip (to clear upper 16 bits of %eip).
- */
- ljmp *(realptr - entry16)
-3:
-DEBUG_CHAR('g')
- /* we are in real mode now
- * set up the real mode segment registers : %ds, $ss, %es
- */
- /* Setup the data segment */
- movw %cs, %ax
- movw %ax, %ds
-
-DEBUG_CHAR('h')
- /* Load the registers */
- movl eax - entry16, %eax
- movl ebx - entry16, %ebx
- movl ecx - entry16, %ecx
- movl edx - entry16, %edx
- movl esi - entry16, %esi
- movl edi - entry16, %esi
- movl esp - entry16, %esp
- movl ebp - entry16, %ebp
- movw es - entry16, %es
- movw ss - entry16, %ss
- movw fs - entry16, %fs
- movw gs - entry16, %gs
- movw ds - entry16, %ds
-
- /* Jump to the kernel entrypoint */
- ljmp %cs:*(realdest - entry16)
-
- .balign 4
-entry16_regs:
-eax: .long 0x00000000
-ebx: .long 0x00000000
-ecx: .long 0x00000000
-edx: .long 0x00000000
-esi: .long 0x00000000
-edi: .long 0x00000000
-esp: .long 0x00000000
-ebp: .long 0x00000000
-ds: .word 0x0000
-es: .word 0x0000
-ss: .word 0x0000
-fs: .word 0x0000
-gs: .word 0x0000
-realdest:
-ip: .word 0x0000
-cs: .word 0x0000
- .size entry16_regs, . - entry16_regs
-
- .balign 16
-realptr:
- .word 3b - entry16
- .word 0x0000
-
- .data
- .balign 4
-
-idtptr:
- /* 256 entry idt at 0 */
- .word 0x400 - 1
- .word 0, 0
-
-gdt:
- /* 0x00 unusable segment so used as the gdt ptr */
- .word gdt_end - gdt - 1
- .long gdt
- .word 0
-
- /* 0x08 16 bit real mode code segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x9b, 0x00, 0x00
-
- /* 0x10 16 bit real mode data segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x93, 0x00, 0x00
-gdt_end:
-/*
- * kexec: Linux boots Linux
- *
- * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation (version 2 of the License).
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#if 1
-#define TTYS0_BASE 0x3f8
-#define TTYS0_RBR (TTYS0_BASE+0x00)
-#define TTYS0_TBR TTYS0_RBR
-#define TTYS0_LSR (TTYS0_BASE+0x05)
-
-
- /* uses: ax, dx */
-#define TTYS0_TX_AL \
- mov %al, %ah ; \
-9: mov $TTYS0_LSR, %dx ; \
- inb %dx, %al ; \
- test $0x20, %al ; \
- je 9b ; \
- mov $TTYS0_TBR, %dx ; \
- mov %ah, %al ; \
- outb %al, %dx ; \
-9: mov $TTYS0_LSR, %dx ; \
- inb %dx, %al ; \
- test $0x40, %al ; \
- jz 9b
-
-
-
- /* uses: ax, dx */
-#define TTYS0_TX_CHAR(byte) \
- mov byte, %al ; \
- TTYS0_TX_AL
-
- /* uses: ax, dx */
-#define TTYS0_TX_HEX32(lword) \
- mov lword, %eax ; \
- shr $28, %eax ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $24, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $20, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $16, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $12, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $8, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- shr $4, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL ; \
- ; \
- mov lword, %eax ; \
- and $0x0f, %al ; \
- add $'0', %al ; \
- cmp $'9', %al ; \
- jle 9f ; \
- add $39, %al ; \
-9: ; \
- TTYS0_TX_AL
-
-
-#define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
-#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n')
-#else
-#define DEBUG_CHAR(x)
-#define DEBUG_TX_HEX32(x)
-#endif
-
-.data
- .globl setup16_debug_start, setup16_debug_end, setup16_debug_size, setup16_debug_align
- .globl setup16_debug_regs
- .globl setup16_debug_kernel_pre_protected
- .globl setup16_debug_first_code32
- .globl setup16_debug_old_code32
-setup16_debug_start:
-_reloc = .
- .balign 16
- .code32
-DEBUG_CHAR('a')
- /* Compute where I am running at */
- call 1f
-1: popl %ebx
- subl $(1b - _reloc), %ebx
-
- /* Remember where I am running at */
- movl %ebx, location - _reloc(%ebx)
-
-DEBUG_CHAR('b')
- /* Fixup my real mode segment */
- movl %ebx, %eax
- shrl $4, %eax
- movw %ax, 2 + realptr - _reloc(%ebx)
-
-DEBUG_CHAR('c')
- /* Fixup the gdt */
- movl %ebx, %eax
- shll $16, %eax
-
- movl %ebx, %ecx
- shrl $16, %ecx
- andl $0xff, %ecx
-
- movl %ebx, %edx
- andl $0xff000000, %edx
- orl %edx, %ecx
-
- addl %ebx, gdtaddr - _reloc(%ebx)
- addl %ebx, debug_gdtaddr - _reloc(%ebx)
- orl %eax, 0x08 + gdt - _reloc(%ebx)
- orl %ecx, 0x0c + gdt - _reloc(%ebx)
- orl %eax, 0x10 + gdt - _reloc(%ebx)
- orl %ecx, 0x14 + gdt - _reloc(%ebx)
-
-
-
-DEBUG_CHAR('d')
- /* Setup the classic BIOS interrupt table at 0x0 */
- lidt idtptr - _reloc(%ebx)
-
- /* Provide us with 16bit segments that we can use */
- lgdt gdtptr - _reloc(%ebx)
-
- /* Note we don't disable the a20 line, (this shouldn't be required)
- * The code to do it is in kexec_test and it is a real pain.
- * I will worry about that when I need it.
- */
-
- /* Load 16bit data segments, to ensure the segment limits are set */
- movl $0x10, %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %ss
- movl %eax, %fs
- movl %eax, %gs
-
- /* switch to 16bit mode */
-
- ljmp $0x08, $2f - _reloc
-2:
- .code16
-DEBUG_CHAR('e')
- /* Disable Paging and protected mode */
- /* clear the PG & PE bits of CR0 */
- movl %cr0,%eax
- andl $~((1 << 31)|(1<<0)),%eax
- movl %eax,%cr0
-
-DEBUG_CHAR('f')
- /* make intersegment jmp to flush the processor pipeline
- * and reload %cs:%eip (to clear upper 16 bits of %eip).
- */
- ljmp *(realptr - _reloc)
-3:
-DEBUG_CHAR('g')
- /* we are in real mode now
- * set up the real mode segment registers : %ds, $ss, %es
- */
- /* Setup the data segment */
- movw %cs, %ax
- movw %ax, %ds
-
-DEBUG_CHAR('h')
- /* Load the registers */
- movl eax - _reloc, %eax
- movl ebx - _reloc, %ebx
- movl ecx - _reloc, %ecx
- movl edx - _reloc, %edx
- movl esi - _reloc, %esi
- movl edi - _reloc, %esi
- movl esp - _reloc, %esp
- movl ebp - _reloc, %ebp
- movw es - _reloc, %es
- movw ss - _reloc, %ss
- movw fs - _reloc, %fs
- movw gs - _reloc, %gs
- movw ds - _reloc, %ds
-
- /* Jump to the kernel entrypoint */
- ljmp %cs:*(realdest - _reloc)
-
-setup16_debug_regs:
-eax: .long 0x00000000
-ebx: .long 0x00000000
-ecx: .long 0x00000000
-edx: .long 0x00000000
-esi: .long 0x00000000
-edi: .long 0x00000000
-esp: .long 0x00000000
-ebp: .long 0x00000000
-ds: .word 0x0000
-es: .word 0x0000
-ss: .word 0x0000
-fs: .word 0x0000
-gs: .word 0x0000
-realdest:
-ip: .word 0x0000
-cs: .word 0x0000
-
- .balign 16
-realptr:
- .word 3b - _reloc
- .word 0x0000
-
-idtptr:
- /* 256 entry idt at 0 */
- .word 0x400 - 1
- .word 0, 0
-
-gdtptr:
- .word gdt_end - gdt - 1
-gdtaddr:
- .long gdt - _reloc
-
-gdt:
- /* dummy */
- .word 0, 0, 0, 0
-
- /* 16 bit real mode code segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x9b, 0x00, 0x00
-
- /* 16 bit real mode data segment */
- .word 0xffff, 0x0000
- .byte 0x00, 0x93, 0x00, 0x00
-gdt_end:
-
-debug_gdt:
- /* 0x00 */
- .word debug_gdt_end - debug_gdt - 1
-debug_gdtaddr:
- .long debug_gdt - _reloc
- .word 0
-
- /* 0x08 */
- .word 0, 0, 0, 0 /* Nothing in the first gdt entry */
-
- /* 0x10 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x18 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-
-
- /* 0x20 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x28 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-
-
- /* 0x30 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x38 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-
-
- /* 0x40 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x48 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-
-
- /* 0x50 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x58 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-
-
- /* 0x60 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
- .word 0xFFFF, 0x00, 0x9A00, 0x00CF
- /* 0x68 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
- .word 0xFFFF, 0x0000, 0x9200, 0x00CF
-debug_gdt_end:
-
-
-setup16_debug_kernel_pre_protected:
- .code16
- DEBUG_CHAR('i')
- cli # no interrupts allowed !
- movb $0x80, %al # disable NMI for bootup
- # sequence
- outb %al, $0x70
- lret
-setup16_debug_first_code32:
- .code32
- .byte 0xbf /* movl $0x12345678, %edi */
-location:
- .long 0x12345678
- DEBUG_CHAR('j')
- .byte 0xb8 /* movl $0x10000, %eax */
-setup16_debug_old_code32:
- .long 0x10000
- jmp %eax
-setup16_debug_end:
-setup16_debug_size:
- .long setup16_debug_end - setup16_debug_start
-setup16_debug_align:
- .long 16
diff --git a/purgatory/arch/x86_64/Makefile b/purgatory/arch/x86_64/Makefile
index 22b4228e..73009375 100644
--- a/purgatory/arch/x86_64/Makefile
+++ b/purgatory/arch/x86_64/Makefile
@@ -16,9 +16,11 @@ dist += purgatory/arch/x86_64/Makefile $(x86_64_PURGATORY_SRCS_native) \
purgatory/arch/x86_64/purgatory-x86_64.h
# Don't add sources in i386/ to dist, as i386/Makefile adds them
-x86_64_PURGATORY_SRCS += purgatory/arch/i386/entry32-16.S
+x86_64_PURGATORY_SRCS += purgatory/arch/i386/entry32-16.S
x86_64_PURGATORY_SRCS += purgatory/arch/i386/entry32-16-debug.S
x86_64_PURGATORY_SRCS += purgatory/arch/i386/crashdump_backup.c
x86_64_PURGATORY_SRCS += purgatory/arch/i386/console-x86.c
x86_64_PURGATORY_SRCS += purgatory/arch/i386/vga.c
x86_64_PURGATORY_SRCS += purgatory/arch/i386/pic.c
+
+x86_64_PURGATORY_EXTRA_CFLAGS = -mcmodel=large
diff --git a/purgatory/arch/x86_64/entry64-32.S b/purgatory/arch/x86_64/entry64-32.S
index 66f8a854..f2b63775 100644
--- a/purgatory/arch/x86_64/entry64-32.S
+++ b/purgatory/arch/x86_64/entry64-32.S
@@ -24,13 +24,34 @@
.equ CR0_PG, 0x80000000
.text
+ .balign 16
.globl entry32, entry32_regs
entry32:
.code64
- /* Setup a gdt that should that is generally usefully */
+ /* Setup the 4G offset of entry32 lm_exit code segment */
+ movq $0x00CF9A000000ffff, %rax
+
+ leaq entry32(%rip), %rbx /* Low 24 bits */
+ andq $0xffffff, %rbx
+ shlq $16, %rbx
+ orq %rbx, %rax
+
+ leaq entry32(%rip), %rbx /* High 8 bits */
+ movq $0xff000000, %rdx
+ andq %rdx, %rbx
+ shlq $32, %rbx
+ orq %rbx, %rax
+
+ movq %rax, (gdt + 0x20)(%rip)
+
+ /* Setup a gdt that is generally usefully */
lgdt gdt(%rip)
-
+
+ /* Setup the far pointer to the entry point */
+ movl eip(%rip), %eax
+ movl %eax, entry32_addr(%rip)
+
/* Switch to 32bit compatiblity mode */
ljmp *lm_exit_addr(%rip)
lm_exit:
@@ -60,19 +81,19 @@ lm_exit:
movl %eax, %gs
/* Load the registers */
- movl eax, %eax
- movl ecx, %ecx
- movl edx, %edx
- movl esi, %esi
- movl edi, %edi
- movl esp, %esp
- movl ebp, %ebp
- movl ebx, %ebx
+ movl %cs:eax - entry32, %eax
+ movl %cs:ecx - entry32, %ecx
+ movl %cs:edx - entry32, %edx
+ movl %cs:esi - entry32, %esi
+ movl %cs:edi - entry32, %edi
+ movl %cs:esp - entry32, %esp
+ movl %cs:ebp - entry32, %ebp
+ movl %cs:ebx - entry32, %ebx
/* Jump to the loaded image */
- jmpl *(eip)
+ ljmp *%cs:entry32_addr - entry32
- .section ".rodata"
+ .section ".data"
.balign 16
gdt: /* 0x00 unusable segment
* 0x08 unused
@@ -88,8 +109,8 @@ gdt: /* 0x00 unusable segment
/* 0x18 4GB flat data segment */
.word 0xFFFF, 0x0000, 0x9200, 0x00CF
- /* 0x20 dummy */
- .word 0x0000, 0x0000, 0x0000, 0x000
+ /* 0x20 4GB flat code segment base at entry32 */
+ .word 0xFFFF, 0x0000, 0x9A00, 0x0CF
/* 0x28 dummy */
.word 0x0000, 0x0000, 0x0000, 0x000
/* 0x30 dummy */
@@ -115,9 +136,15 @@ gdt_end:
.section ".rodata"
.balign 4
lm_exit_addr:
- .long lm_exit
- .long 0x10
-
+ .long lm_exit - entry32
+ .long 0x20
+
+ .section ".data"
+ .balign 4
+entry32_addr:
+ .long 0x00000000
+ .long 0x10
+
.section ".rodata"
.balign 4
entry32_regs:
@@ -129,6 +156,9 @@ esi: .long 0x00000000
edi: .long 0x00000000
esp: .long 0x00000000
ebp: .long 0x00000000
-eip: .long entry16
- .size entry32_regs, . - entry32_regs
+eip: .quad entry16 /* low 32 bits address
+ * high 32bits zeros
+ * uses 64bit reloc
+ */
+ .size entry32_regs, (. - 4) - entry32_regs
diff --git a/purgatory/arch/x86_64/entry64.S b/purgatory/arch/x86_64/entry64.S
index 666023c6..e3223b75 100644
--- a/purgatory/arch/x86_64/entry64.S
+++ b/purgatory/arch/x86_64/entry64.S
@@ -37,9 +37,10 @@ entry64:
movl %eax, %fs
movl %eax, %gs
- movq $stack_init, %rsp
+ leaq stack_init(%rip), %rsp
pushq $0x10 /* CS */
- pushq $new_cs_exit
+ leaq new_cs_exit(%rip), %rax
+ pushq %rax
lretq
new_cs_exit:
diff --git a/purgatory/arch/x86_64/setup-x86_64.S b/purgatory/arch/x86_64/setup-x86_64.S
index 74997fa5..95572d8f 100644
--- a/purgatory/arch/x86_64/setup-x86_64.S
+++ b/purgatory/arch/x86_64/setup-x86_64.S
@@ -42,10 +42,10 @@ purgatory_start:
/* In 64bit mode the code segment is meaningless */
movq 0(%rsp), %rax
- movq %rax, jump_back_entry
+ movq %rax, jump_back_entry(%rip)
/* Setup a stack */
- movq $lstack_end, %rsp
+ leaq lstack_end(%rip), %rsp
/* Call the C code */
call purgatory