#include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/boot.h>
+#include <asm/asm-offsets.h>
 
 .section ".text.head","ax",@progbits
        .globl startup_32
 
 startup_32:
-       cld
-       cli
+       /* check to see if KEEP_SEGMENTS flag is meaningful */
+       cmpw $0x207, BP_version(%esi)
+       jb 1f
+
+       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
+        * us to not reload segments */
+       testb $(1<<6), BP_loadflags(%esi)
+       jnz 2f
+
+1:     cli
        movl $(__BOOT_DS),%eax
        movl %eax,%ds
        movl %eax,%es
        movl %eax,%gs
        movl %eax,%ss
 
+2:     cld
+
 /* Calculate the delta between where we were compiled to run
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
 
        # Part 2 of the header, from the old setup.S
 
                .ascii  "HdrS"          # header signature
-               .word   0x0206          # header version number (>= 0x0105)
+               .word   0x0207          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
                                                 #added with boot protocol
                                                 #version 2.06
 
+hardware_subarch:      .long 0                 # subarchitecture, added with 2.07
+                                               # default to 0 for normal x86 PC
+
+hardware_subarch_data: .quad 0
+
 # End of setup header #####################################################
 
        .section ".inittext", "ax"
 
  */
 .section .text.head,"ax",@progbits
 ENTRY(startup_32)
+       /* check to see if KEEP_SEGMENTS flag is meaningful */
+       cmpw $0x207, BP_version(%esi)
+       jb 1f
+
+       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
+               us to not reload segments */
+       testb $(1<<6), BP_loadflags(%esi)
+       jnz 2f
 
 /*
  * Set segments to known values.
  */
-       cld
-       lgdt boot_gdt_descr - __PAGE_OFFSET
+1:     lgdt boot_gdt_descr - __PAGE_OFFSET
        movl $(__BOOT_DS),%eax
        movl %eax,%ds
        movl %eax,%es
        movl %eax,%fs
        movl %eax,%gs
+2:
 
 /*
  * Clear BSS first so that there are no surprises...
- * No need to cld as DF is already clear from cld above...
  */
+       cld
        xorl %eax,%eax
        movl $__bss_start - __PAGE_OFFSET,%edi
        movl $__bss_stop - __PAGE_OFFSET,%ecx
        movsl
 1:
 
+#ifdef CONFIG_PARAVIRT
+       cmpw $0x207, (boot_params + BP_version - __PAGE_OFFSET)
+       jb default_entry
+
+       /* Paravirt-compatible boot parameters.  Look to see what architecture
+               we're booting under. */
+       movl (boot_params + BP_hardware_subarch - __PAGE_OFFSET), %eax
+       cmpl $num_subarch_entries, %eax
+       jae bad_subarch
+
+       movl subarch_entries - __PAGE_OFFSET(,%eax,4), %eax
+       subl $__PAGE_OFFSET, %eax
+       jmp *%eax
+
+bad_subarch:
+WEAK(lguest_entry)
+WEAK(xen_entry)
+       /* Unknown implementation; there's really
+          nothing we can do at this point. */
+       ud2a
+.data
+subarch_entries:
+       .long default_entry             /* normal x86/PC */
+       .long lguest_entry              /* lguest hypervisor */
+       .long xen_entry                 /* Xen hypervisor */
+num_subarch_entries = (. - subarch_entries) / 4
+.previous
+#endif /* CONFIG_PARAVIRT */
+
 /*
  * Initialize page tables.  This creates a PDE and a set of page
  * tables, which are located immediately beyond _end.  The variable
  */
 page_pde_offset = (__PAGE_OFFSET >> 20);
 
+default_entry:
        movl $(pg0 - __PAGE_OFFSET), %edi
        movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
        movl $0x007, %eax                       /* 0x007 = PRESENT+RW+USER */