From ed396c068b881877330f7d40bfce02db9b1199b3 Mon Sep 17 00:00:00 2001
From: Frans Kaashoek <kaashoek@mit.edu>
Date: Wed, 1 Feb 2017 18:04:13 -0500
Subject: [PATCH] Eliminate code for gs trick to track per-cpu state.  We rely
 on lapiccpunum() to find a per-cpu id with which we locate a cpu's cpu
 struct.

---
 defs.h    |  1 +
 lapic.c   | 14 ++------------
 main.c    |  2 +-
 mmu.h     |  9 ++++-----
 proc.c    | 34 +++++++++++++++++++++++-----------
 proc.h    | 30 +-----------------------------
 trapasm.S |  3 ---
 vm.c      |  7 +------
 8 files changed, 33 insertions(+), 67 deletions(-)

diff --git a/defs.h b/defs.h
index 5e049ae..c4870d0 100644
--- a/defs.h
+++ b/defs.h
@@ -108,6 +108,7 @@ void            exit(void);
 int             fork(void);
 int             growproc(int);
 int             kill(int);
+struct cpu*     mycpu(void);
 struct proc*    myproc();
 void            pinit(void);
 void            procdump(void);
diff --git a/lapic.c b/lapic.c
index 9039665..9a12f17 100644
--- a/lapic.c
+++ b/lapic.c
@@ -98,22 +98,12 @@ lapicinit(void)
   lapicw(TPR, 0);
 }
 
+// Should be called with interrupts disabled: the calling thread shouldn't be
+// rescheduled between reading lapic[ID] and checking against cpu array.
 int
 lapiccpunum(void)
 {
   int apicid, i;
-  
-  // Cannot call cpunum when interrupts are enabled:
-  // result not guaranteed to last long enough to be used!
-  // Would prefer to panic but even printing is chancy here:
-  // almost everything, including cprintf and panic, calls cpu,
-  // often indirectly through acquire and release.
-  if(readeflags()&FL_IF){
-    static int n;
-    if(n++ == 0)
-      cprintf("cpunum called from %x with interrupts enabled\n",
-        __builtin_return_address(0));
-  }
 
   if (!lapic)
     return 0;
diff --git a/main.c b/main.c
index d7e59cf..e5b7d64 100644
--- a/main.c
+++ b/main.c
@@ -53,7 +53,7 @@ mpenter(void)
 static void
 mpmain(void)
 {
-  cprintf("cpu%d: starting %d\n", cpuid(), lapiccpunum());
+  cprintf("cpu%d: starting %d\n", cpuid(), cpuid());
   idtinit();       // load idt register
   xchg(&(mycpu()->started), 1); // tell startothers() we're up
   scheduler();     // start running processes
diff --git a/mmu.h b/mmu.h
index e732ccd..a1afa9f 100644
--- a/mmu.h
+++ b/mmu.h
@@ -42,13 +42,12 @@
 // various segment selectors.
 #define SEG_KCODE 1  // kernel code
 #define SEG_KDATA 2  // kernel data+stack
-#define SEG_KCPU  3  // kernel per-cpu data
-#define SEG_UCODE 4  // user code
-#define SEG_UDATA 5  // user data+stack
-#define SEG_TSS   6  // this process's task state
+#define SEG_UCODE 3  // user code
+#define SEG_UDATA 4  // user data+stack
+#define SEG_TSS   5  // this process's task state
 
 // cpu->gdt[NSEGS] holds the above segments.
-#define NSEGS     7
+#define NSEGS     6
 
 //PAGEBREAK!
 #ifndef __ASSEMBLER__
diff --git a/proc.c b/proc.c
index 4e8f461..6445725 100644
--- a/proc.c
+++ b/proc.c
@@ -26,12 +26,29 @@ pinit(void)
   initlock(&ptable.lock, "ptable");
 }
 
-// XXX get rid off?
+// Must be called with interrupts disabled
 int
 cpuid() {
   return mycpu()-cpus;
 }
 
+// Must be called with interrupts disabled
+struct cpu*
+mycpu(void)
+{
+  // Would prefer to panic but even printing is chancy here: almost everything,
+  // including cprintf and panic, calls mycpu(), often indirectly through
+  // acquire and release.
+  if(readeflags()&FL_IF){
+    static int n;
+    if(n++ == 0)
+      cprintf("mycpu called from %x with interrupts enabled\n",
+        __builtin_return_address(0));
+  }
+
+  return &cpus[lapiccpunum()];
+}
+
 // Disable interrupts so that we are not rescheduled
 // while reading proc from the cpu structure
 struct proc*
@@ -304,7 +321,8 @@ scheduler(void)
 {
   struct proc *p;
   struct cpu *c = mycpu();
-
+  c->proc = 0;
+  
   for(;;){
     // Enable interrupts on this processor.
     sti();
@@ -321,15 +339,13 @@ scheduler(void)
       c->proc = p;
       switchuvm(p);
       p->state = RUNNING;
-      p->cpu = c;
-      // cprintf("%d: switch to %d\n", c-cpus, p->pid);
-      swtch(&(p->cpu->scheduler), p->context);
+
+      swtch(&(c->scheduler), p->context);
       switchkvm();
 
       // Process is done running for now.
       // It should have changed its p->state before coming back.
       c->proc = 0;
-      p->cpu = 0;
     }
     release(&ptable.lock);
 
@@ -358,9 +374,7 @@ sched(void)
   if(readeflags()&FL_IF)
     panic("sched interruptible");
   intena = mycpu()->intena;
-  // cprintf("%d: before swtch %d %x\n", p->cpu-cpus, p->pid, * (int *) 0x1d);
-  swtch(&p->context, p->cpu->scheduler);
-  // cprintf("%d/%d: after swtch %d %x\n", cpuid(), p->cpu-cpus, p->pid, * (int *) 0x1d);
+  swtch(&p->context, mycpu()->scheduler);
   mycpu()->intena = intena;
 }
 
@@ -422,8 +436,6 @@ sleep(void *chan, struct spinlock *lk)
   p->chan = chan;
   p->state = SLEEPING;
 
-  // cprintf("sleep %d\n", p->pid);
-  
   sched();
 
   // Tidy up.
diff --git a/proc.h b/proc.h
index 7047d54..1647114 100644
--- a/proc.h
+++ b/proc.h
@@ -7,39 +7,12 @@ struct cpu {
   volatile uint started;       // Has the CPU started?
   int ncli;                    // Depth of pushcli nesting.
   int intena;                  // Were interrupts enabled before pushcli?
-  // Per-CPU variables, holding pointers to the current cpu and to the current
-  // process (see cpu() and proc() in proc.c)
-  struct cpu *cpu;             // On cpu 0, cpu = &cpus[0]; on cpu 1, cpu=&cpus[1], etc.
-  struct proc *proc;           // The currently-running process on this cpu
+  struct proc *proc;           // The process running on this cpu or null
 };
 
 extern struct cpu cpus[NCPU];
 extern int ncpu;
 
-// The asm suffix tells gcc to use "%gs:0" to refer to cpu
-// and "%gs:4" to refer to proc.  seginit sets up the
-// %gs segment register so that %gs refers to the memory
-// holding those two variables in the local cpu's struct cpu.
-// This is similar to how thread-local variables are implemented
-// in thread libraries such as Linux pthreads.
-
-static inline struct cpu*
-mycpu(void) {
-  struct cpu *cpu;
-  asm("movl %%gs:0, %0" : "=r"(cpu));
-  return cpu;
-}
-
-#if 0
-static inline struct proc*
-myproc(void) {
-  struct proc *proc;
-  asm("movl %%gs:4, %0" : "=r"(proc));
-  return proc;
-}
-#endif
-
-
 //PAGEBREAK: 17
 // Saved registers for kernel context switches.
 // Don't need to save all the segment registers (%cs, etc),
@@ -76,7 +49,6 @@ struct proc {
   struct file *ofile[NOFILE];  // Open files
   struct inode *cwd;           // Current directory
   char name[16];               // Process name (debugging)
-  struct cpu *cpu;             // If running, which cpu.
 };
 
 // Process memory is laid out contiguously, low addresses first:
diff --git a/trapasm.S b/trapasm.S
index 787727f..2271d27 100644
--- a/trapasm.S
+++ b/trapasm.S
@@ -14,9 +14,6 @@ alltraps:
   movw $(SEG_KDATA<<3), %ax
   movw %ax, %ds
   movw %ax, %es
-  movw $(SEG_KCPU<<3), %ax
-  movw %ax, %fs
-  movw %ax, %gs
 
   # Call trap(tf), where tf=%esp
   pushl %esp
diff --git a/vm.c b/vm.c
index d1640e8..9ac7401 100644
--- a/vm.c
+++ b/vm.c
@@ -21,17 +21,12 @@ seginit(void)
   // Cannot share a CODE descriptor for both kernel and user
   // because it would have to have DPL_USR, but the CPU forbids
   // an interrupt from CPL=0 to DPL=3.
-  c = &cpus[lapiccpunum()];
+  c = &cpus[cpuid()];
   c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0);
   c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0);
   c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, DPL_USER);
   c->gdt[SEG_UDATA] = SEG(STA_W, 0, 0xffffffff, DPL_USER);
-  c->cpu = c;
-  c->proc = 0;
-  // Map cpu and proc -- these are private per cpu.
-  c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 4, 0);
   lgdt(c->gdt, sizeof(c->gdt));
-  loadgs(SEG_KCPU << 3);
 }
 
 // Return the address of the PTE in page table pgdir