diff --git a/bootasm.S b/bootasm.S
index 9c4a9b2e3270f3ab82ff659dc4d6bdc437b205e3..4b2e01295f5cb7f32fcb6bc1300736ef113509fd 100644
--- a/bootasm.S
+++ b/bootasm.S
@@ -7,7 +7,6 @@
 
 #define SEG_KCODE 1  // kernel code
 #define SEG_KDATA 2  // kernel data+stack
-#define SEG_KCPU  3  // kernel per-cpu data
 
 #define CR0_PE    1  // protected mode enable bit
 
@@ -63,7 +62,7 @@ start32:
   movw    %ax, %ds                # -> DS: Data Segment
   movw    %ax, %es                # -> ES: Extra Segment
   movw    %ax, %ss                # -> SS: Stack Segment
-  movw    $(SEG_KCPU<<3), %ax     # Our per-cpu segment selector
+  movw    $0, %ax                 # Zero segments not ready for use
   movw    %ax, %fs                # -> FS
   movw    %ax, %gs                # -> GS
 
diff --git a/proc.c b/proc.c
index a2aeab2884906b4c06ce6878d071be426c4fae03..dd7d8818de199d8a45ccb49c703783a511734442 100644
--- a/proc.c
+++ b/proc.c
@@ -93,9 +93,9 @@ ksegment(void)
   c1->gdt[SEG_UDATA] = SEG_NULL;
   c1->gdt[SEG_TSS] = SEG_NULL;
   lgdt(c1->gdt, sizeof(c1->gdt));
+  loadfsgs(SEG_KCPU << 3);
   
   // Initialize cpu-local variables.
-  setgs(SEG_KCPU << 3);
   c = c1;
   cp = 0;
 }
diff --git a/trapasm.S b/trapasm.S
index 59fca57cea1cf43ceacaf28b5ef0cb3ad4a10a78..983163dc35caed8b946a5c6392d2864681a9c86e 100644
--- a/trapasm.S
+++ b/trapasm.S
@@ -13,10 +13,7 @@ alltraps:
   pushal
   
   # Set up data and per-cpu segments.
-  # Can find out KDATA from %ss.
-  # Assume that KCPU is KDATA+1.
   movw $(SEG_KDATA<<3), %ax
-  movw %ss, %ax
   movw %ax, %ds
   movw %ax, %es
   movw $(SEG_KCPU<<3), %ax
diff --git a/x86.h b/x86.h
index ecb5d2a8fce5821c93fc10ba220ce4c0316881c1..934b9eced0dce95233d7ebe360ca1e72958ed2a3 100644
--- a/x86.h
+++ b/x86.h
@@ -104,9 +104,10 @@ xchg(volatile uint *addr, uint newval)
 }
 
 static inline void
-setgs(ushort gs)
+loadfsgs(ushort v)
 {
-  asm volatile("movw %0, %%gs" : : "r" (gs));
+  asm volatile("movw %0, %%fs" : : "r" (v));
+  asm volatile("movw %0, %%gs" : : "r" (v));
 }
 
 static inline void