# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1313744093 -3600
# Node ID dd90b59cb11c60c48e174c899190e2967341fe32
# Parent  29aeed4979a78f26519f5fde8a405f8438297ab9
x86: trampoline cleanup

To make future changes less error prone, and to slightly simplify a
possible future conversion to a relocatable trampoline even for the
multiboot path (pretty desirable given that we had to change the
trampoline base a number of times to escape collisions with firmware
placed data),
- remove final uses of bootsym_phys() from trampoline.S, allowing the
  symbol to be undefined before including this file (to make sure no
  new references get added)
- replace two easy to deal with uses of bootsym_phys() in head.S
- remove an easy to replace reference to BOOT_TRAMPOLINE

Signed-off-by: Jan Beulich <jbeulich@novell.com>

# HG changeset patch
# User Jan Beulich <jbeulich@suse.com>
# Date 1339424128 -3600
# Node ID 61dfb3da56b0a3ac86f81f4a8770e11e1dbc2aa9
# Parent  6d1a30dc47e8dfcb826ff14c833d694fd4e6afb2
x86: get rid of BOOT_TRAMPOLINE

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>

Committed-by: Keir Fraser <keir@xen.org>

Index: xen-4.1.4-testing/xen/arch/x86/boot/Makefile
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/Makefile
+++ xen-4.1.4-testing/xen/arch/x86/boot/Makefile
@@ -2,8 +2,7 @@ obj-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
Index: xen-4.1.4-testing/xen/arch/x86/boot/build32.mk
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/build32.mk
+++ xen-4.1.4-testing/xen/arch/x86/boot/build32.mk
@@ -15,9 +15,10 @@ CFLAGS += -Werror -fno-builtin -msoft-fl
 	$(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
Index: xen-4.1.4-testing/xen/arch/x86/boot/cmdline.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/cmdline.S
+++ xen-4.1.4-testing/xen/arch/x86/boot/cmdline.S
@@ -165,14 +165,14 @@ cmdline_parse_early:
         call    .Lfind_option
         test    %eax,%eax
         setnz   %al
-        or      %al,bootsym_phys(skip_realmode)
+        or      %al,sym_phys(skip_realmode)
 
         /* Check for 'tboot=' command-line option. */
         movl    $sym_phys(.Ltboot_opt),4(%esp)
         call    .Lfind_option
         test    %eax,%eax
         setnz   %al
-        or      %al,bootsym_phys(skip_realmode) /* tboot= implies no-real-mode */
+        or      %al,sym_phys(skip_realmode) /* tboot= implies no-real-mode */
 
 .Lparse_edd:
         /* Check for 'edd=' command-line option. */
@@ -183,13 +183,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. */
@@ -205,17 +205,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. */
@@ -229,7 +229,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
@@ -253,7 +253,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:
@@ -272,7 +272,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
@@ -281,7 +281,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
@@ -290,9 +290,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:
@@ -309,7 +309,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:
@@ -322,7 +322,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
Index: xen-4.1.4-testing/xen/arch/x86/boot/head.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/head.S
+++ xen-4.1.4-testing/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,17 +215,32 @@ __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     $bootsym_phys(trampoline_start),%edi
         mov     $trampoline_end - trampoline_start,%ecx
         rep     movsb
 
-        mov     $bootsym_phys(early_stack),%esp
-        call    cmdline_parse_early
-
         /* Jump into the relocated trampoline. */
-        jmp     $BOOT_CS32,$bootsym_phys(trampoline_boot_cpu_entry)
+        lret
 
 #include "cmdline.S"
 
Index: xen-4.1.4-testing/xen/arch/x86/boot/reloc.c
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/reloc.c
+++ xen-4.1.4-testing/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)
Index: xen-4.1.4-testing/xen/arch/x86/boot/trampoline.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/trampoline.S
+++ xen-4.1.4-testing/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
@@ -132,7 +139,7 @@ high_start:
 
         .code32
 trampoline_boot_cpu_entry:
-        cmpb    $0,bootsym_phys(skip_realmode)
+        cmpb    $0,bootsym_rel(skip_realmode,5)
         jnz     .Lskip_realmode
 
         /* Load pseudo-real-mode segments. */
@@ -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)
-1:      mov     $(BOOT_TRAMPOLINE>>4),%ax
+        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
 
@@ -195,7 +202,7 @@ trampoline_boot_cpu_entry:
         lmsw    %ax                       # CR0.PE = 1 (enter protected mode)
 
         /* Load proper protected-mode values into all segment registers. */
-        ljmpl   $BOOT_CS32,$bootsym_phys(1f)
+        ljmpl   $BOOT_CS32,$bootsym_rel(1f,6)
         .code32
 1:      mov     $BOOT_DS,%eax
         mov     %eax,%ds
@@ -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:
Index: xen-4.1.4-testing/xen/arch/x86/boot/wakeup.S
===================================================================
--- xen-4.1.4-testing.orig/xen/arch/x86/boot/wakeup.S
+++ xen-4.1.4-testing/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:
