[PATCH] i386: always clear bss

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When the paravirt dispatcher gets run immediately on entry to
startup_32, the bss isn't cleared.  This happens to work if the
hypervisor's domain builder loaded the complete kernel image and
cleared the bss for us, but this may not always be true (for example,
if we're running out of a decompressed bzImage).

Change head.S so that it unconditionally clears the bss before doing
the paravirt dispatch or continuing on to normal native boot.

There are a couple of points to note:
 - We can't, in general, load the segment registers before paravirt
   dispatch, because we could be running with a non-standard gdt and
   segment selectors.  In practice though, all code which ends up
   jumping into startup_32 will have already set the segment registers
   up to sane values, so we don't need to do it again.
 - Paging may or may not be enabled, and if enabled we may or may not
   be mapped to the proper kernel virtual address.  To deal with this,
   we compare the kernel's linked address with where we're actually
   running, and use that to offset the bss pointer.

Signed-off-by: Jeremy Fitzhardinge <[email protected]>
Cc: Rusty Russell <[email protected]>
Cc: Eric W. Biederman <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>

---
 arch/i386/kernel/head.S |   48 ++++++++++++++++++++++++++---------------------
 1 file changed, 27 insertions(+), 21 deletions(-)

===================================================================
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -70,6 +70,33 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + 
  */
 .section .text.head,"ax",@progbits
 ENTRY(startup_32)
+/*
+ * Clear BSS first so that there are no surprises...
+ * This relies on the the segment registers to be set
+ * to something sensible, which will have already happened.
+ */
+	cld
+	xorl %eax,%eax
+	movl $__bss_start,%edi
+	movl $__bss_stop,%ecx
+	subl %edi,%ecx
+	shrl $2,%ecx
+	/*
+	 * Work out whether we're running mapped or not:
+	 * - call a local label
+	 * - pop the return address to get the actual eip
+	 * - subtract local label from %edi (= bss pointer)
+	 * - add in actual eip
+	 *
+	 * This will result in %edi being a virtual pointer if
+	 * we're currently mapped, or a physical pointer if we're
+	 * not (either no paging or 1:1 mapping).
+	 */
+	call 1f
+1:	popl %ebx
+	subl $1b, %edi
+	addl %ebx, %edi
+	rep ; stosl
 
 #ifdef CONFIG_PARAVIRT
         movl %cs, %eax
@@ -77,27 +104,6 @@ ENTRY(startup_32)
         jnz startup_paravirt
 #endif
 
-/*
- * Set segments to known values.
- */
-	cld
-	lgdt boot_gdt_descr - __PAGE_OFFSET
-	movl $(__BOOT_DS),%eax
-	movl %eax,%ds
-	movl %eax,%es
-	movl %eax,%fs
-	movl %eax,%gs
-
-/*
- * Clear BSS first so that there are no surprises...
- * No need to cld as DF is already clear from cld above...
- */
-	xorl %eax,%eax
-	movl $__bss_start - __PAGE_OFFSET,%edi
-	movl $__bss_stop - __PAGE_OFFSET,%ecx
-	subl %edi,%ecx
-	shrl $2,%ecx
-	rep ; stosl
 /*
  * Copy bootup parameters out of the way.
  * Note: %esi still has the pointer to the real-mode data.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux