diff options
| author | rsc <rsc> | 2007-08-27 22:53:31 +0000 | 
|---|---|---|
| committer | rsc <rsc> | 2007-08-27 22:53:31 +0000 | 
| commit | 99b11b6c64c17b94288c659e9398261e69a0cf75 (patch) | |
| tree | c45cb8b500f14dbe69c3cba41dfa66766e589a63 /lapic.c | |
| parent | b63bb0fd00cb34ed1d776e6836f5a2bb90de98c1 (diff) | |
| download | xv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.tar.gz xv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.tar.bz2 xv6-labs-99b11b6c64c17b94288c659e9398261e69a0cf75.zip | |
Simplify MP hardware code.
Mainly delete unused constants and code.
Move mp_startthem to main.c as bootothers.
Diffstat (limited to 'lapic.c')
| -rw-r--r-- | lapic.c | 153 | 
1 files changed, 62 insertions, 91 deletions
| @@ -1,132 +1,91 @@ +// The local APIC manages internal (non-I/O) interrupts. +// See Chapter 8 & Appendix C of Intel processor manual volume 3. +  #include "types.h" -#include "mp.h"  #include "defs.h"  #include "param.h"  #include "x86.h"  #include "traps.h"  #include "mmu.h"  #include "proc.h" -#include "lapic.h"  // Local APIC registers, divided by 4 for use as uint[] indices.  #define ID      (0x0020/4)   // ID  #define VER     (0x0030/4)   // Version  #define TPR     (0x0080/4)   // Task Priority -#define APR     (0x0090/4)   // Arbitration Priority -#define PPR     (0x00A0/4)   // Processor Priority  #define EOI     (0x00B0/4)   // EOI -#define LDR     (0x00D0/4)   // Logical Destination -#define DFR     (0x00E0/4)   // Destination Format  #define SVR     (0x00F0/4)   // Spurious Interrupt Vector -#define ISR     (0x0100/4)   // Interrupt Status (8 registers) -#define TMR     (0x0180/4)   // Trigger Mode (8 registers) -#define IRR     (0x0200/4)   // Interrupt Request (8 registers) +  #define ENABLE     0x00000100   // Unit Enable  #define ESR     (0x0280/4)   // Error Status  #define ICRLO   (0x0300/4)   // Interrupt Command +  #define INIT       0x00000500   // INIT/RESET +  #define STARTUP    0x00000600   // Startup IPI +  #define DELIVS     0x00001000   // Delivery status +  #define ASSERT     0x00004000   // Assert interrupt (vs deassert) +  #define LEVEL      0x00008000   // Level triggered +  #define BCAST      0x00080000   // Send to all APICs, including self.  #define ICRHI   (0x0310/4)   // Interrupt Command [63:32]  #define TIMER   (0x0320/4)   // Local Vector Table 0 (TIMER) +  #define X1         0x0000000B   // divide counts by 1 +  #define PERIODIC   0x00020000   // Periodic  #define PCINT   (0x0340/4)   // Performance Counter LVT  #define LINT0   (0x0350/4)   // Local Vector Table 1 (LINT0)  #define LINT1   (0x0360/4)   // Local Vector Table 2 (LINT1)  #define ERROR   (0x0370/4)   // Local Vector Table 3 (ERROR) +  #define MASKED     0x00010000   // Interrupt masked  #define TICR    (0x0380/4)   // Timer Initial Count  #define TCCR    (0x0390/4)   // Timer Current Count  #define TDCR    (0x03E0/4)   // Timer Divide Configuration -// SVR   -#define ENABLE     0x00000100   // Unit Enable -#define FOCUS      0x00000200   // Focus Processor Checking Disable - -// ICRLO -// [14] IPI Trigger Mode Level (RW) -#define DEASSERT   0x00000000   // Deassert level-sensitive interrupt -#define ASSERT     0x00004000   // Assert level-sensitive interrupt - -// [17:16] Remote Read Status -#define INVALID    0x00000000   // Invalid -#define WAIT       0x00010000   // In-Progress -#define VALID      0x00020000   // Valid - -// [19:18] Destination Shorthand -#define FIELD      0x00000000   // No shorthand -#define SELF       0x00040000   // Self is single destination -#define ALLINC     0x00080000   // All including self -#define ALLEXC     0x000C0000   // All Excluding self - -// ESR -#define SENDCS     0x00000001   // Send CS Error -#define RCVCS      0x00000002   // Receive CS Error -#define SENDACCEPT 0x00000004   // Send Accept Error -#define RCVACCEPT  0x00000008   // Receive Accept Error -#define SENDVECTOR 0x00000020   // Send Illegal Vector -#define RCVVECTOR  0x00000040   // Receive Illegal Vector -#define REGISTER   0x00000080   // Illegal Register Address - -// [17] Timer Mode (RW) -#define ONESHOT    0x00000000   // One-shot -#define PERIODIC   0x00020000   // Periodic - -// [19:18] Timer Base (RW) -#define CLKIN      0x00000000   // use CLKIN as input -#define TMBASE     0x00040000   // use TMBASE -#define DIVIDER    0x00080000   // use output of the divider - -#define X2         0x00000000   // divide by 2 -#define X4         0x00000001   // divide by 4 -#define X8         0x00000002   // divide by 8 -#define X16        0x00000003   // divide by 16 -#define X32        0x00000008   // divide by 32 -#define X64        0x00000009   // divide by 64 -#define X128       0x0000000A   // divide by 128 -#define X1         0x0000000B   // divide by 1 - -//PAGEBREAK!  volatile uint *lapic;  // Initialized in mp.c +//PAGEBREAK!  void  lapic_init(int c)  { -  uint r, lvt; -    if(!lapic)       return; -  lapic[DFR] = 0xFFFFFFFF;    // Set dst format register -  r = (lapic[ID]>>24) & 0xFF; // Read APIC ID -  lapic[LDR] = (1<<r) << 24; -  lapic[TPR] = 0xFF;          // No interrupts for now - -  // Enable APIC +  // Enable local APIC; set spurious interrupt vector.    lapic[SVR] = ENABLE | (IRQ_OFFSET+IRQ_SPURIOUS); -  // In virtual wire mode, set up the LINT0 and LINT1 as follows: -  lapic[LINT0] = APIC_IMASK | APIC_EXTINT; -  lapic[LINT1] = APIC_IMASK | APIC_NMI; +  // The timer repeatedly counts down at bus frequency +  // from lapic[TICR] and then issues an interrupt.   +  // Lapic[TCCR] is the current counter value. +  // If xv6 cared more about precise timekeeping, the +  // values of TICR and TCCR would be calibrated using +  // an external time source. +  lapic[TDCR] = X1; +  lapic[TICR] = 10000000; +  lapic[TCCR] = 10000000; +  lapic[TIMER] = PERIODIC | (IRQ_OFFSET + IRQ_TIMER); -  lapic[EOI] = 0; // Ack any outstanding interrupts. +  // Disable logical interrupt lines. +  lapic[LINT0] = MASKED; +  lapic[LINT1] = MASKED; -  lvt = (lapic[VER]>>16) & 0xFF; -  if(lvt >= 4) -    lapic[PCINT] = APIC_IMASK; +  // Disable performance counter overflow interrupts +  // on machines that provide that interrupt entry. +  if(((lapic[VER]>>16) & 0xFF) >= 4) +    lapic[PCINT] = MASKED; + +  // Map error interrupt to IRQ_ERROR.    lapic[ERROR] = IRQ_OFFSET+IRQ_ERROR; + +  // Clear error status register (requires back-to-back writes).    lapic[ESR] = 0; -  lapic[ESR]; +  lapic[ESR] = 0; + +  // Ack any outstanding interrupts. +  lapic[EOI] = 0; -  // Issue an INIT Level De-Assert to synchronise arbitration ID's. +  // Send an Init Level De-Assert to synchronise arbitration ID's.    lapic[ICRHI] = 0; -  lapic[ICRLO] = ALLINC | APIC_LEVEL | -                       DEASSERT | APIC_INIT; -  while(lapic[ICRLO] & APIC_DELIVS) +  lapic[ICRLO] = BCAST | INIT | LEVEL; +  while(lapic[ICRLO] & DELIVS)      ; -  // Initialize the interrupt timer. -  // On real hardware would need to do more XXX. -  lapic[TDCR] = X1; -  lapic[TIMER] = CLKIN | PERIODIC | (IRQ_OFFSET + IRQ_TIMER); -  lapic[TCCR] = 10000000; -  lapic[TICR] = 10000000; - -  // Enable interrupts on the APIC (but not on processor). +  // Enable interrupts on the APIC (but not on the processor).    lapic[TPR] = 0;  } @@ -146,22 +105,34 @@ lapic_eoi(void)      lapic[EOI] = 0;  } +// Spin for a given number of microseconds. +// On real hardware would want to tune this dynamically. +static void +microdelay(int us) +{ +  volatile int j = 0; +   +  while(us-- > 0) +    for(j=0; j<10000; j++); +} +  // Start additional processor running bootstrap code at addr. +// See Appendix B of MultiProcessor Specification.  void  lapic_startap(uchar apicid, uint addr)  {    int i;    volatile int j = 0; +  // Send INIT interrupt to reset other CPU.    lapic[ICRHI] = apicid<<24; -  lapic[ICRLO] = FIELD | APIC_LEVEL | ASSERT | APIC_INIT; -  for(j=0; j<10000; j++);  // 200us -  lapic[ICRLO] = FIELD | APIC_LEVEL | DEASSERT | APIC_INIT; -  for(j=0; j<1000000; j++);  // 10ms - +  lapic[ICRLO] = INIT | LEVEL; +  microdelay(10); +   +  // Send startup IPI (twice!) to enter bootstrap code.    for(i = 0; i < 2; i++){      lapic[ICRHI] = apicid<<24; -    lapic[ICRLO] = FIELD | APIC_EDGE | APIC_STARTUP | (addr/4096); +    lapic[ICRLO] = STARTUP | (addr>>12);      for(j=0; j<10000; j++);  // 200us    }  } | 
