]> Devi Nivas Git - cs3210-lab0.git/commitdiff
and the file
authorkaashoek <kaashoek>
Wed, 12 Jul 2006 17:19:24 +0000 (17:19 +0000)
committerkaashoek <kaashoek>
Wed, 12 Jul 2006 17:19:24 +0000 (17:19 +0000)
lapic.c [new file with mode: 0644]

diff --git a/lapic.c b/lapic.c
new file mode 100644 (file)
index 0000000..a4dac30
--- /dev/null
+++ b/lapic.c
@@ -0,0 +1,204 @@
+#include "types.h"
+#include "mp.h"
+#include "defs.h"
+#include "memlayout.h"
+#include "param.h"
+#include "x86.h"
+#include "traps.h"
+#include "mmu.h"
+#include "proc.h"
+
+
+/* 
+ * Credit: Plan 9 sources, Intel MP spec, and Cliff Frey
+ */
+
+enum {                                 /* Local APIC registers */
+  LAPIC_ID  = 0x0020,  /* ID */
+  LAPIC_VER = 0x0030,  /* Version */
+  LAPIC_TPR = 0x0080,  /* Task Priority */
+  LAPIC_APR = 0x0090,  /* Arbitration Priority */
+  LAPIC_PPR = 0x00A0,  /* Processor Priority */
+  LAPIC_EOI = 0x00B0,  /* EOI */
+  LAPIC_LDR = 0x00D0,  /* Logical Destination */
+  LAPIC_DFR = 0x00E0,  /* Destination Format */
+  LAPIC_SVR = 0x00F0,  /* Spurious Interrupt Vector */
+  LAPIC_ISR = 0x0100,  /* Interrupt Status (8 registers) */
+  LAPIC_TMR = 0x0180,  /* Trigger Mode (8 registers) */
+  LAPIC_IRR = 0x0200,  /* Interrupt Request (8 registers) */
+  LAPIC_ESR = 0x0280,  /* Error Status */
+  LAPIC_ICRLO = 0x0300,        /* Interrupt Command */
+  LAPIC_ICRHI = 0x0310,        /* Interrupt Command [63:32] */
+  LAPIC_TIMER = 0x0320,        /* Local Vector Table 0 (TIMER) */
+  LAPIC_PCINT = 0x0340,        /* Performance Counter LVT */
+  LAPIC_LINT0 = 0x0350,        /* Local Vector Table 1 (LINT0) */
+  LAPIC_LINT1 = 0x0360,        /* Local Vector Table 2 (LINT1) */
+  LAPIC_ERROR = 0x0370,        /* Local Vector Table 3 (ERROR) */
+  LAPIC_TICR = 0x0380, /* Timer Initial Count */
+  LAPIC_TCCR = 0x0390, /* Timer Current Count */
+  LAPIC_TDCR = 0x03E0, /* Timer Divide Configuration */
+};
+
+enum {                                 /* LAPIC_SVR */
+  LAPIC_ENABLE = 0x00000100,   /* Unit Enable */
+  LAPIC_FOCUS  = 0x00000200,   /* Focus Processor Checking Disable */
+};
+
+enum {                                 /* LAPIC_ICRLO */
+                                       /* [14] IPI Trigger Mode Level (RW) */
+  LAPIC_DEASSERT = 0x00000000, /* Deassert level-sensitive interrupt */
+  LAPIC_ASSERT = 0x00004000,   /* Assert level-sensitive interrupt */
+
+  /* [17:16] Remote Read Status */
+  LAPIC_INVALID        = 0x00000000,   /* Invalid */
+  LAPIC_WAIT   = 0x00010000,   /* In-Progress */
+  LAPIC_VALID  = 0x00020000,   /* Valid */
+
+  /* [19:18] Destination Shorthand */
+  LAPIC_FIELD  = 0x00000000,   /* No shorthand */
+  LAPIC_SELF   = 0x00040000,   /* Self is single destination */
+  LAPIC_ALLINC = 0x00080000,   /* All including self */
+  LAPIC_ALLEXC = 0x000C0000,   /* All Excluding self */
+};
+
+enum {                                 /* LAPIC_ESR */
+  LAPIC_SENDCS = 0x00000001,   /* Send CS Error */
+  LAPIC_RCVCS  = 0x00000002,   /* Receive CS Error */
+  LAPIC_SENDACCEPT = 0x00000004,       /* Send Accept Error */
+  LAPIC_RCVACCEPT = 0x00000008,        /* Receive Accept Error */
+  LAPIC_SENDVECTOR = 0x00000020,       /* Send Illegal Vector */
+  LAPIC_RCVVECTOR = 0x00000040,        /* Receive Illegal Vector */
+  LAPIC_REGISTER = 0x00000080, /* Illegal Register Address */
+};
+
+enum {                                 /* LAPIC_TIMER */
+                                       /* [17] Timer Mode (RW) */
+  LAPIC_ONESHOT        = 0x00000000,   /* One-shot */
+  LAPIC_PERIODIC = 0x00020000, /* Periodic */
+
+  /* [19:18] Timer Base (RW) */
+  LAPIC_CLKIN  = 0x00000000,   /* use CLKIN as input */
+  LAPIC_TMBASE = 0x00040000,   /* use TMBASE */
+  LAPIC_DIVIDER        = 0x00080000,   /* use output of the divider */
+};
+
+enum {                                 /* LAPIC_TDCR */
+  LAPIC_X2 = 0x00000000,       /* divide by 2 */
+  LAPIC_X4 = 0x00000001,       /* divide by 4 */
+  LAPIC_X8 = 0x00000002,       /* divide by 8 */
+  LAPIC_X16 = 0x00000003,      /* divide by 16 */
+  LAPIC_X32 = 0x00000008,      /* divide by 32 */
+  LAPIC_X64 = 0x00000009,      /* divide by 64 */
+  LAPIC_X128 = 0x0000000A,     /* divide by 128 */
+  LAPIC_X1 = 0x0000000B,       /* divide by 1 */
+};
+
+uint32_t *lapicaddr;
+
+static int
+lapic_read(int r)
+{
+  return *(lapicaddr+(r/sizeof(*lapicaddr)));
+}
+
+static void
+lapic_write(int r, int data)
+{
+  *(lapicaddr+(r/sizeof(*lapicaddr))) = data;
+}
+
+
+void
+lapic_timerinit()
+{
+  cprintf("%d: init timer\n", cpu());
+  lapic_write(LAPIC_TDCR, LAPIC_X1);
+  lapic_write(LAPIC_TIMER, LAPIC_CLKIN | LAPIC_PERIODIC | (IRQ_OFFSET + IRQ_TIMER));
+  lapic_write(LAPIC_TCCR, 10000000);
+  lapic_write(LAPIC_TICR, 10000000);
+}
+
+void
+lapic_timerintr()
+{
+  cprintf("%d: timer interrupt!\n", cpu());
+  lapic_write (LAPIC_EOI, 0);
+}
+
+void
+lapic_init(int c)
+{
+  uint32_t r, lvt;
+
+  cprintf("lapic_init %d\n", c);
+
+  lapic_write(LAPIC_DFR, 0xFFFFFFFF); // set destination format register
+  r = (lapic_read(LAPIC_ID)>>24) & 0xFF; // read APIC ID
+  lapic_write(LAPIC_LDR, (1<<r)<<24);  // set logical destination register to r
+  lapic_write(LAPIC_TPR, 0xFF);  // no interrupts for now
+  lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS));  // enable APIC
+
+  // in virtual wire mode, set up the LINT0 and LINT1 as follows:
+  lapic_write(LAPIC_LINT0, APIC_IMASK | APIC_EXTINT);
+  lapic_write(LAPIC_LINT1, APIC_IMASK | APIC_NMI);
+
+  lapic_write(LAPIC_EOI, 0); // acknowledge any outstanding interrupts.
+
+  lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF;
+  if(lvt >= 4)
+    lapic_write(LAPIC_PCINT, APIC_IMASK);
+  lapic_write(LAPIC_ERROR, IRQ_OFFSET+IRQ_ERROR);
+  lapic_write(LAPIC_ESR, 0);
+  lapic_read(LAPIC_ESR);
+
+  /*
+   * Issue an INIT Level De-Assert to synchronise arbitration ID's.
+   */
+  lapic_write(LAPIC_ICRHI, 0);
+  lapic_write(LAPIC_ICRLO, LAPIC_ALLINC|APIC_LEVEL|LAPIC_DEASSERT|APIC_INIT);
+  while(lapic_read(LAPIC_ICRLO) & APIC_DELIVS)
+    ;
+
+  cprintf("Done init of an apic\n");
+}
+
+void
+lapic_enableintr(void) 
+{
+  lapic_write(LAPIC_TPR, 0);
+}
+
+void
+lapic_disableintr(void) 
+{
+  lapic_write(LAPIC_TPR, 0xFF);
+}
+
+int
+cpu(void)
+{
+  return (lapic_read(LAPIC_ID)>>24) & 0xFF;
+}
+
+void
+lapic_startap(uint8_t apicid, int v)
+{
+  int crhi, i;
+  volatile int j = 0;
+
+  crhi = apicid<<24;
+  lapic_write(LAPIC_ICRHI, crhi);
+  lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL|LAPIC_ASSERT|APIC_INIT);
+
+  while (j++ < 10000) {;}
+  lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_LEVEL|LAPIC_DEASSERT|APIC_INIT);
+
+  while (j++ < 1000000) {;}
+
+  // in p9 code, this was i < 2, which is what the spec says on page B-3
+  for(i = 0; i < 1; i++){
+    lapic_write(LAPIC_ICRHI, crhi);
+    lapic_write(LAPIC_ICRLO, LAPIC_FIELD|APIC_EDGE|APIC_STARTUP|(v/PGSIZE));
+    while (j++ < 100000) {;}
+  }
+}