We recently saw a machine that has the EBDA extending as low as 0x7c000,
so that Xen fails to boot after relocating the trampoline. To fix this,
I removed BOOT_TRAMPOLINE and bootsym_phys completely.
Here are the parts:
1) the trampoline segment is set to 64k below the EBDA. head.S grows
the ability to relocate the trampoline segment
2) reloc.c is made position-independent. It allocates data below the
trampoline, whose address is passed in _eax.
3) cmdline.S is called before relocating, so all bootsym_phys there
become sym_phys.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
jb: - fall back to low memory size (instead of segment 0x7c00) if EBDA
value is out of range
- also add upper limit check on EBDA value
- fix and simplify inline assembly operands in reloc_mbi_struct()
- use lret instead of retf
- renamed early_stack to wakeup_stack, defined and used now only
in wakeup.S
- aligned reloc.bin''s end of .text to 16 bytes, so that checking
__bss_start == end works reliably
Signed-off-by: Jan Beulich <jbeulich@suse.com>
--- a/xen/arch/x86/boot/Makefile
+++ b/xen/arch/x86/boot/Makefile
@@ -2,8 +2,7 @@ obj-bin-y += head.o
head.o: reloc.S
-BOOT_TRAMPOLINE := $(shell sed -n
''s,^\#define[[:space:]]\{1\,\}BOOT_TRAMPOLINE[[:space:]]\{1\,\},,p''
head.S)
%.S: %.c
- RELOC=$(BOOT_TRAMPOLINE) $(MAKE) -f build32.mk $@
+ $(MAKE) -f build32.mk $@
reloc.S: head.S
--- a/xen/arch/x86/boot/build32.mk
+++ b/xen/arch/x86/boot/build32.mk
@@ -16,9 +16,10 @@ CFLAGS := $(filter-out -flto,$(CFLAGS))
$(OBJCOPY) -O binary $< $@
%.lnk: %.o
- $(LD) $(LDFLAGS_DIRECT) -N -Ttext $(RELOC) -o $@ $<
+ $(LD) $(LDFLAGS_DIRECT) -N -Ttext 0 -o $@ $<
%.o: %.c
- $(CC) $(CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) -c -fpic $< -o $@
reloc.o: $(BASEDIR)/include/asm-x86/config.h
+.PRECIOUS: %.bin %.lnk
--- a/xen/arch/x86/boot/cmdline.S
+++ b/xen/arch/x86/boot/cmdline.S
@@ -164,13 +164,13 @@ cmdline_parse_early:
pushl MB_cmdline(%ebx)
call .Lfind_option
test %eax,%eax
- setnz bootsym_phys(skip_realmode)
+ setnz sym_phys(skip_realmode)
/* Check for ''tboot='' command-line option. */
movl $sym_phys(.Ltboot_opt),4(%esp)
call .Lfind_option
test %eax,%eax
- setnz bootsym_phys(skip_realmode) /* tboot= implies no-real-mode */
+ setnz sym_phys(skip_realmode) /* tboot= implies no-real-mode */
.Lparse_edd:
/* Check for ''edd='' command-line option. */
@@ -181,13 +181,13 @@ cmdline_parse_early:
cmpb $''='',3(%eax)
jne .Lparse_edid
add $4,%eax
- movb $2,bootsym_phys(opt_edd) /* opt_edd=2: edd=off */
+ movb $2,sym_phys(opt_edd) /* opt_edd=2: edd=off */
cmpw $0x666f,(%eax) /* 0x666f == "of" */
je .Lparse_edid
- decb bootsym_phys(opt_edd) /* opt_edd=1: edd=skipmbr */
+ decb sym_phys(opt_edd) /* opt_edd=1: edd=skipmbr */
cmpw $0x6b73,(%eax) /* 0x6b73 == "sk" */
je .Lparse_edid
- decb bootsym_phys(opt_edd) /* opt_edd=0: edd=on (default) */
+ decb sym_phys(opt_edd) /* opt_edd=0: edd=on (default) */
.Lparse_edid:
/* Check for ''edid='' command-line option. */
@@ -203,17 +203,17 @@ cmdline_parse_early:
pushl $sym_phys(.Ledid_force)
call .Lstr_prefix
add $8,%esp
- movb $2,bootsym_phys(opt_edid) /* opt_edid=2: edid=force */
+ movb $2,sym_phys(opt_edid) /* opt_edid=2: edid=force */
test %eax,%eax
jz .Lparse_vga
push %ebx
pushl $sym_phys(.Ledid_no)
call .Lstr_prefix
add $8,%esp
- decb bootsym_phys(opt_edid) /* opt_edid=1: edid=no */
+ decb sym_phys(opt_edid) /* opt_edid=1: edid=no */
test %eax,%eax
jz .Lparse_vga
- decb bootsym_phys(opt_edid) /* opt_edid=0: default */
+ decb sym_phys(opt_edid) /* opt_edid=0: default */
.Lparse_vga:
/* Check for ''vga='' command-line option. */
@@ -227,7 +227,7 @@ cmdline_parse_early:
add $4,%eax
/* Found the ''vga='' option. Default option is to
display vga menu. */
- movw $ASK_VGA,bootsym_phys(boot_vid_mode)
+ movw $ASK_VGA,sym_phys(boot_vid_mode)
/* Check for ''vga=text-80x<rows>. */
mov %eax,%ebx
@@ -251,7 +251,7 @@ cmdline_parse_early:
cmp %ax,%bx
lodsw
jne 1b
- mov %ax,bootsym_phys(boot_vid_mode)
+ mov %ax,sym_phys(boot_vid_mode)
jmp .Lcmdline_exit
.Lparse_vga_gfx:
@@ -270,7 +270,7 @@ cmdline_parse_early:
push %ebx
call .Latoi
pop %esi
- mov %ax,bootsym_phys(vesa_size)+0
+ mov %ax,sym_phys(vesa_size)+0
/* skip ''x'' */
lodsb
cmpb $''x'',%al
@@ -279,7 +279,7 @@ cmdline_parse_early:
push %esi
call .Latoi
pop %esi
- mov %ax,bootsym_phys(vesa_size)+2
+ mov %ax,sym_phys(vesa_size)+2
/* skip ''x'' */
lodsb
cmpb $''x'',%al
@@ -288,9 +288,9 @@ cmdline_parse_early:
push %esi
call .Latoi
pop %esi
- mov %ax,bootsym_phys(vesa_size)+4
+ mov %ax,sym_phys(vesa_size)+4
/* commit to vesa mode */
- movw $VIDEO_VESA_BY_SIZE,bootsym_phys(boot_vid_mode)
+ movw $VIDEO_VESA_BY_SIZE,sym_phys(boot_vid_mode)
jmp .Lcmdline_exit
.Lparse_vga_mode:
@@ -307,7 +307,7 @@ cmdline_parse_early:
push %ebx
call .Latoi
add $4,%esp
- mov %ax,bootsym_phys(boot_vid_mode)
+ mov %ax,sym_phys(boot_vid_mode)
jmp .Lcmdline_exit
.Lparse_vga_current:
@@ -320,7 +320,7 @@ cmdline_parse_early:
jnz .Lcmdline_exit
/* We have ''vga=current''. */
- movw $VIDEO_CURRENT_MODE,bootsym_phys(boot_vid_mode)
+ movw $VIDEO_CURRENT_MODE,sym_phys(boot_vid_mode)
.Lcmdline_exit:
popa
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -9,9 +9,7 @@
.text
.code32
-#define BOOT_TRAMPOLINE 0x7c000
#define sym_phys(sym) ((sym) - __XEN_VIRT_START)
-#define bootsym_phys(sym) ((sym) - trampoline_start + BOOT_TRAMPOLINE)
#define BOOT_CS32 0x0008
#define BOOT_CS64 0x0010
@@ -79,6 +77,23 @@ __start:
cmp $0x2BADB002,%eax
jne not_multiboot
+ /* Set up trampoline segment 64k below EBDA */
+ movzwl 0x40e,%eax /* EBDA segment */
+ cmp $0xa000,%eax /* sanity check (high) */
+ jae 0f
+ cmp $0x4000,%eax /* sanity check (low) */
+ jae 1f
+0:
+ movzwl 0x413,%eax /* use base memory size on failure */
+ shl $10-4,%eax
+1:
+ sub $0x1000,%eax
+
+ /* From arch/x86/smpboot.c: start_eip had better be page-aligned! */
+ xor %al, %al
+ shl $4, %eax
+ mov %eax,sym_phys(trampoline_phys)
+
/* Save the Multiboot info struct (after relocation) for later use. */
mov $sym_phys(cpu0_stack)+1024,%esp
push %ebx
@@ -190,7 +205,7 @@ __start:
#endif
/* Apply relocations to bootstrap trampoline. */
- mov $BOOT_TRAMPOLINE,%edx
+ mov sym_phys(trampoline_phys),%edx
mov $sym_phys(__trampoline_rel_start),%edi
mov %edx,sym_phys(trampoline_phys)
1:
@@ -200,22 +215,35 @@ __start:
cmp $sym_phys(__trampoline_rel_stop),%edi
jb 1b
+ /* Patch in the trampoline segment. */
+ shr $4,%edx
+ mov $sym_phys(__trampoline_seg_start),%edi
+1:
+ mov (%edi),%eax
+ mov %dx,(%edi,%eax)
+ add $4,%edi
+ cmp $sym_phys(__trampoline_seg_stop),%edi
+ jb 1b
+
+ call cmdline_parse_early
+
+ /* Switch to low-memory stack. */
+ mov sym_phys(trampoline_phys),%edi
+ lea 0x10000(%edi),%esp
+ lea trampoline_boot_cpu_entry-trampoline_start(%edi),%eax
+ pushl $BOOT_CS32
+ push %eax
+
/* Copy bootstrap trampoline to low memory, below 1MB. */
mov $sym_phys(trampoline_start),%esi
- mov %edx,%edi
mov $trampoline_end - trampoline_start,%ecx
rep movsb
- lea early_stack-trampoline_start(%edx),%esp
- call cmdline_parse_early
-
/* Jump into the relocated trampoline. */
- jmp $BOOT_CS32,$bootsym_phys(trampoline_boot_cpu_entry)
+ lret
#include "cmdline.S"
-#undef bootsym_phys
-
reloc:
#include "reloc.S"
--- a/xen/arch/x86/boot/reloc.c
+++ b/xen/arch/x86/boot/reloc.c
@@ -10,42 +10,49 @@
* Keir Fraser <keir@xen.org>
*/
+/* entered with %eax = BOOT_TRAMPOLINE */
asm (
" .text \n"
" .globl _start \n"
"_start: \n"
- " mov $_start,%edi \n"
" call 1f \n"
- "1: pop %esi \n"
- " sub $1b-_start,%esi \n"
- " mov $__bss_start-_start,%ecx \n"
- " rep movsb \n"
- " xor %eax,%eax \n"
- " mov $_end,%ecx \n"
- " sub %edi,%ecx \n"
- " rep stosb \n"
- " mov $reloc,%eax \n"
- " jmp *%eax \n"
+ "1: pop %ebx \n"
+ " mov %eax,alloc-1b(%ebx) \n"
+ " mov $_end,%ecx \n" /* check that BSS is
empty! */
+ " sub $__bss_start,%ecx \n"
+ " jz reloc \n"
+ "1: jmp 1b \n"
+ );
+
+/* This is our data. Because the code must be relocatable, no BSS is
+ * allowed. All data is accessed PC-relative with inline assembly.
+ */
+asm (
+ "alloc: \n"
+ " .long 0 \n"
+ " .subsection 1 \n"
+ " .p2align 4, 0xcc \n"
+ " .subsection 0 \n"
);
typedef unsigned int u32;
#include "../../../include/xen/multiboot.h"
-extern char _start[];
-
-static void *memcpy(void *dest, const void *src, unsigned int n)
-{
- char *s = (char *)src, *d = dest;
- while ( n-- )
- *d++ = *s++;
- return dest;
-}
-
static void *reloc_mbi_struct(void *old, unsigned int bytes)
{
- static void *alloc = &_start;
- alloc = (void *)(((unsigned long)alloc - bytes) & ~15ul);
- return memcpy(alloc, old, bytes);
+ void *new;
+ asm(
+ " call 1f \n"
+ "1: pop %%edx \n"
+ " mov alloc-1b(%%edx),%0 \n"
+ " sub %1,%0 \n"
+ " and $~15,%0 \n"
+ " mov %0,alloc-1b(%%edx) \n"
+ " mov %0,%%edi \n"
+ " rep movsb \n"
+ : "=&r" (new), "+c" (bytes), "+S"
(old)
+ : : "edx", "edi");
+ return new;
}
static char *reloc_mbi_string(char *old)
--- a/xen/arch/x86/boot/trampoline.S
+++ b/xen/arch/x86/boot/trampoline.S
@@ -11,6 +11,13 @@
.long 111b - (off) - .; \
.popsection
+#define bootsym_segrel(sym, off) \
+ $0,$bootsym(sym); \
+111:; \
+ .pushsection .trampoline_seg, "a"; \
+ .long 111b - (off) - .; \
+ .popsection
+
.globl trampoline_realmode_entry
trampoline_realmode_entry:
mov %cs,%ax
@@ -151,14 +158,14 @@ trampoline_boot_cpu_entry:
1: mov %eax,%cr0 # CR0.PE = 0 (leave protected mode)
/* Load proper real-mode values into %cs, %ds, %es and %ss. */
- ljmp $(BOOT_TRAMPOLINE>>4),$bootsym(1f)
+ ljmp bootsym_segrel(1f,2)
1: mov %cs,%ax
mov %ax,%ds
mov %ax,%es
mov %ax,%ss
/* Initialise stack pointer and IDT, and enable irqs. */
- mov $bootsym(early_stack),%sp
+ xor %sp,%sp
lidt bootsym(rm_idt)
sti
@@ -220,7 +227,3 @@ rm_idt: .word 256*4-1, 0, 0
#include "edd.S"
#include "video.S"
#include "wakeup.S"
-
- .align 16
- .fill PAGE_SIZE,1,0
-early_stack:
--- a/xen/arch/x86/boot/wakeup.S
+++ b/xen/arch/x86/boot/wakeup.S
@@ -11,7 +11,7 @@ ENTRY(wakeup_start)
movw %cs, %ax
movw %ax, %ds
movw %ax, %ss # A stack required for BIOS call
- movw $wakesym(early_stack), %sp
+ movw $wakesym(wakeup_stack), %sp
pushl $0 # Kill dangerous flag early
popfl
@@ -101,7 +101,7 @@ real_magic: .long 0x12345678
.globl video_mode, video_flags
video_mode: .long 0
video_flags: .long 0
-trampoline_seg: .word BOOT_TRAMPOLINE >> 4
+trampoline_seg: .word 0
.pushsection .trampoline_seg, "a"
.long trampoline_seg - .
.popsection
@@ -116,7 +116,7 @@ wakeup_32:
mov $BOOT_DS, %eax
mov %eax, %ds
mov %eax, %ss
- mov $bootsym_rel(early_stack, 4, %esp)
+ mov $bootsym_rel(wakeup_stack, 4, %esp)
# check saved magic again
mov $sym_phys(saved_magic), %eax
@@ -188,3 +188,7 @@ ret_point:
bogus_saved_magic:
movw $0x0e00 + ''S'', 0xb8014
jmp bogus_saved_magic
+
+ .align 16
+ .fill PAGE_SIZE,1,0
+wakeup_stack:
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel