ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

apic.c
Go to the documentation of this file.
00001 /*
00002  *  ReactOS kernel
00003  *  Copyright (C) 2004, 2005 ReactOS Team
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019 /* $Id: apic.c 45565 2010-02-10 23:24:59Z tkreuzer $
00020  *
00021  * COPYRIGHT:   See COPYING in the top level directory
00022  * PROJECT:     ReactOS kernel
00023  * FILE:        hal/halx86/mp/apic.c
00024  * PURPOSE:     
00025  * PROGRAMMER:  
00026  */
00027 
00028 /* INCLUDE ***********************************************************************/
00029 
00030 #include <hal.h>
00031 #include <halfuncs.h> /* Not in PCH because only used for MP HAL */
00032 #include <rtlfuncs.h> /* Not in PCH because only used for MP HAL */
00033 #define NDEBUG
00034 #include <debug.h>
00035 
00036 /* GLOBALS ***********************************************************************/
00037 
00038 ULONG CPUCount;                 /* Total number of CPUs */
00039 ULONG BootCPU;                  /* Bootstrap processor */
00040 ULONG OnlineCPUs;               /* Bitmask of online CPUs */
00041 CPU_INFO CPUMap[MAX_CPU];           /* Map of all CPUs in the system */
00042 
00043 #ifdef CONFIG_SMP
00044 PULONG BIOSBase;                /* Virtual address of BIOS data segment */
00045 PULONG CommonBase;              /* Virtual address of common area */
00046 #endif
00047 
00048 PULONG APICBase = (PULONG)APIC_DEFAULT_BASE;    /* Virtual address of local APIC */
00049 
00050 ULONG APICMode;                 /* APIC mode at startup */
00051 
00052 /* For debugging */
00053 ULONG lastregr[MAX_CPU];
00054 ULONG lastvalr[MAX_CPU];
00055 ULONG lastregw[MAX_CPU];
00056 ULONG lastvalw[MAX_CPU];
00057 
00058 #ifdef CONFIG_SMP
00059 #include <pshpack1.h>
00060 typedef struct _COMMON_AREA_INFO
00061 {
00062    ULONG Stack;         /* Location of AP stack */
00063    ULONG PageDirectory;     /* Page directory for an AP */
00064    ULONG NtProcessStartup;  /* Kernel entry point for an AP */
00065    ULONG PaeModeEnabled;    /* PAE mode is enabled */
00066    ULONG Debug[16];     /* For debugging */
00067 } COMMON_AREA_INFO, *PCOMMON_AREA_INFO;
00068 #include <poppack.h>
00069 #endif
00070 
00071 extern CHAR *APstart, *APend;
00072 
00073 #define BIOS_AREA   0x0
00074 #define COMMON_AREA 0x2000
00075 
00076 #define HZ      (100)
00077 #define APIC_DIVISOR    (16)
00078 
00079 #define CMOS_READ(address) { \
00080    WRITE_PORT_UCHAR((PUCHAR)0x70, address)); \
00081    READ_PORT_UCHAR((PUCHAR)0x71)); \
00082 }
00083 
00084 #define CMOS_WRITE(address, value) { \
00085    WRITE_PORT_UCHAR((PUCHAR)0x70, address); \
00086    WRITE_PORT_UCHAR((PUCHAR)0x71, value); \
00087 }
00088 
00089 extern ULONG_PTR KernelBase;
00090 
00091 /* FUNCTIONS *********************************************************************/
00092 
00093 extern ULONG Read8254Timer(VOID);
00094 extern VOID WaitFor8254Wraparound(VOID);
00095 extern VOID MpsTimerInterrupt(VOID);
00096 extern VOID MpsErrorInterrupt(VOID);
00097 extern VOID MpsSpuriousInterrupt(VOID);
00098 extern VOID MpsIpiInterrupt(VOID);
00099 
00100 ULONG APICGetMaxLVT(VOID)
00101 {
00102   ULONG tmp, ver, maxlvt;
00103 
00104   tmp = APICRead(APIC_VER);
00105   ver = GET_APIC_VERSION(tmp);
00106   /* 82489DXs do not report # of LVT entries. */
00107   maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(tmp) : 2;
00108 
00109   return maxlvt;
00110 }
00111 
00112 VOID APICClear(VOID)
00113 {
00114   ULONG tmp, maxlvt;
00115 
00116   maxlvt = APICGetMaxLVT();
00117 
00118   /*
00119    * Careful: we have to set masks only first to deassert
00120    * any level-triggered sources.
00121    */
00122 
00123   if (maxlvt >= 3) 
00124   {
00125     tmp = ERROR_VECTOR;
00126     APICWrite(APIC_LVT3, tmp | APIC_LVT3_MASKED);
00127   }
00128 
00129   tmp = APICRead(APIC_LVTT);
00130   APICWrite(APIC_LVTT, tmp | APIC_LVT_MASKED);
00131 
00132   tmp = APICRead(APIC_LINT0);
00133   APICWrite(APIC_LINT0, tmp | APIC_LVT_MASKED);
00134 
00135   tmp = APICRead(APIC_LINT1);
00136   APICWrite(APIC_LINT1, tmp | APIC_LVT_MASKED);
00137 
00138   if (maxlvt >= 4) 
00139   {
00140     tmp = APICRead(APIC_LVTPC);
00141     APICWrite(APIC_LVTPC, tmp | APIC_LVT_MASKED);
00142   }
00143 #if 0
00144   if (maxlvt >= 5)
00145   {
00146     tmp = APICRead(APIC_LVTTHMR);
00147     APICWrite(APIC_LVTTHMR, tmp | APIC_LVT_MASKED);
00148   }
00149 #endif
00150   /*
00151    * Clean APIC state for other OSs:
00152    */
00153   APICWrite(APIC_LVTT, APIC_LVT_MASKED);
00154   APICWrite(APIC_LINT0, APIC_LVT_MASKED);
00155   APICWrite(APIC_LINT1, APIC_LVT_MASKED);
00156 
00157   if (maxlvt >= 3) 
00158   {
00159     APICWrite(APIC_LVT3, APIC_LVT3_MASKED);
00160   }
00161 
00162   if (maxlvt >= 4) 
00163   {
00164     APICWrite(APIC_LVTPC, APIC_LVT_MASKED);
00165   }
00166 #if 0
00167   if (maxlvt >= 5) 
00168   {
00169     APICWrite(APIC_LVTTHMR, APIC_LVT_MASKED);
00170   }
00171 #endif
00172 }
00173 
00174 /* Enable symetric I/O mode ie. connect the BSP's local APIC to INT and NMI lines */
00175 VOID EnableApicMode(VOID)
00176 {
00177    /*
00178     * Do not trust the local APIC being empty at bootup.
00179     */
00180    APICClear();
00181 
00182    WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
00183    WRITE_PORT_UCHAR((PUCHAR)0x23, 0x01);
00184 }
00185 
00186 /* Disable symetric I/O mode ie. go to PIC mode */
00187 __inline VOID DisableSMPMode(VOID)
00188 {
00189    /*
00190     * Put the board back into PIC mode (has an effect
00191     * only on certain older boards).  Note that APIC
00192     * interrupts, including IPIs, won't work beyond
00193     * this point!  The only exception are INIT IPIs.
00194     */
00195    WRITE_PORT_UCHAR((PUCHAR)0x22, 0x70);
00196    WRITE_PORT_UCHAR((PUCHAR)0x23, 0x00);
00197 }
00198 
00199 VOID DumpESR(VOID)
00200 {
00201   ULONG tmp;
00202 
00203   if (APICGetMaxLVT() > 3)
00204   {
00205     APICWrite(APIC_ESR, 0);
00206   }
00207   tmp = APICRead(APIC_ESR);
00208   DbgPrint("ESR %08x\n", tmp);
00209 }
00210 
00211 
00212 VOID APICDisable(VOID)
00213 {
00214   ULONG tmp;
00215 
00216   APICClear();
00217 
00218   /*
00219    * Disable APIC (implies clearing of registers for 82489DX!).
00220    */
00221   tmp = APICRead(APIC_SIVR);
00222   tmp &= ~APIC_SIVR_ENABLE;
00223   APICWrite(APIC_SIVR, tmp);
00224 }
00225 
00226 static VOID APICDumpBit(ULONG base)
00227 {
00228     ULONG v, i, j;
00229 
00230     DbgPrint("0123456789abcdef0123456789abcdef\n");
00231     for (i = 0; i < 8; i++) 
00232     {
00233         v = APICRead(base + i*0x10);
00234         for (j = 0; j < 32; j++) 
00235         {
00236             if (v & (1<<j))
00237                 DbgPrint("1");
00238             else
00239                 DbgPrint("0");
00240         }
00241         DbgPrint("\n");
00242     }
00243 }
00244 
00245 
00246 VOID APICDump(VOID)
00247 /*
00248  * Dump the contents of the local APIC registers
00249  */
00250 {
00251   ULONG v, ver, maxlvt;
00252   ULONG r1, r2, w1, w2;
00253   ULONG CPU = ThisCPU();
00254 
00255 
00256   r1 = lastregr[CPU];
00257   r2 = lastvalr[CPU];
00258   w1 = lastregw[CPU];
00259   w2 = lastvalw[CPU];
00260 
00261   DbgPrint("\nPrinting local APIC contents on CPU(%d):\n", ThisCPU());
00262   v = APICRead(APIC_ID);
00263   DbgPrint("... ID     : %08x (%01x) ", v, GET_APIC_ID(v));
00264   v = APICRead(APIC_VER);
00265   DbgPrint("... VERSION: %08x\n", v);
00266   ver = GET_APIC_VERSION(v);
00267   maxlvt = APICGetMaxLVT();
00268 
00269   v = APICRead(APIC_TPR);
00270   DbgPrint("... TPR    : %08x (%02x)", v, v & ~0);
00271 
00272   if (APIC_INTEGRATED(ver)) 
00273   {
00274      /* !82489DX */
00275      v = APICRead(APIC_APR);
00276      DbgPrint("... APR    : %08x (%02x)\n", v, v & ~0);
00277      v = APICRead(APIC_PPR);
00278      DbgPrint("... PPR    : %08x\n", v);
00279   }
00280 
00281   v = APICRead(APIC_EOI);
00282   DbgPrint("... EOI    : %08x  !  ", v);
00283   v = APICRead(APIC_LDR);
00284   DbgPrint("... LDR    : %08x\n", v);
00285   v = APICRead(APIC_DFR);
00286   DbgPrint("... DFR    : %08x  !  ", v);
00287   v = APICRead(APIC_SIVR);
00288   DbgPrint("... SIVR   : %08x\n", v);
00289 
00290   if (0)
00291   {
00292     DbgPrint("... ISR field:\n");
00293     APICDumpBit(APIC_ISR);
00294     DbgPrint("... TMR field:\n");
00295     APICDumpBit(APIC_TMR);
00296     DbgPrint("... IRR field:\n");
00297     APICDumpBit(APIC_IRR);
00298   }
00299 
00300   if (APIC_INTEGRATED(ver)) 
00301   {
00302      /* !82489DX */
00303      if (maxlvt > 3)        
00304      {
00305     /* Due to the Pentium erratum 3AP. */
00306     APICWrite(APIC_ESR, 0);
00307      }
00308      v = APICRead(APIC_ESR);
00309      DbgPrint("... ESR    : %08x\n", v);
00310   }
00311  
00312   v = APICRead(APIC_ICR0);
00313   DbgPrint("... ICR0   : %08x  !  ", v);
00314   v = APICRead(APIC_ICR1);
00315   DbgPrint("... ICR1   : %08x  !  ", v);
00316 
00317   v = APICRead(APIC_LVTT);
00318   DbgPrint("... LVTT   : %08x\n", v);
00319 
00320   if (maxlvt > 3) 
00321   {
00322      /* PC is LVT#4. */
00323      v = APICRead(APIC_LVTPC);
00324      DbgPrint("... LVTPC  : %08x  !  ", v);
00325   }
00326   v = APICRead(APIC_LINT0);
00327   DbgPrint("... LINT0  : %08x  !  ", v);
00328   v = APICRead(APIC_LINT1);
00329   DbgPrint("... LINT1  : %08x\n", v);
00330 
00331   if (maxlvt > 2) 
00332   {
00333      v = APICRead(APIC_LVT3);
00334      DbgPrint("... LVT3   : %08x\n", v);
00335   }
00336 
00337   v = APICRead(APIC_ICRT);
00338   DbgPrint("... ICRT   : %08x  !  ", v);
00339   v = APICRead(APIC_CCRT);
00340   DbgPrint("... CCCT   : %08x  !  ", v);
00341   v = APICRead(APIC_TDCR);
00342   DbgPrint("... TDCR   : %08x\n", v);
00343   DbgPrint("\n");
00344   DbgPrint("Last register read (offset): 0x%08X\n", r1);
00345   DbgPrint("Last register read (value): 0x%08X\n", r2);
00346   DbgPrint("Last register written (offset): 0x%08X\n", w1);
00347   DbgPrint("Last register written (value): 0x%08X\n", w2);
00348   DbgPrint("\n");
00349 }
00350 
00351 BOOLEAN VerifyLocalAPIC(VOID)
00352 {
00353    SIZE_T reg0, reg1;
00354    LARGE_INTEGER MsrValue;
00355 
00356    /* The version register is read-only in a real APIC */
00357    reg0 = APICRead(APIC_VER);
00358    DPRINT1("Getting VERSION: %x\n", reg0);
00359    APICWrite(APIC_VER, reg0 ^ APIC_VER_MASK);
00360    reg1 = APICRead(APIC_VER);
00361    DPRINT1("Getting VERSION: %x\n", reg1);
00362 
00363    /*
00364     * The two version reads above should print the same
00365     * numbers.  If the second one is different, then we
00366     * poke at a non-APIC.
00367     */
00368 
00369    if (reg1 != reg0)
00370    {
00371       return FALSE;
00372    }
00373 
00374    /*
00375     * Check if the version looks reasonably.
00376     */
00377    reg1 = GET_APIC_VERSION(reg0);
00378    if (reg1 == 0x00 || reg1 == 0xff)
00379    {
00380       return FALSE;
00381    }
00382    reg1 = APICGetMaxLVT();
00383    if (reg1 < 0x02 || reg1 == 0xff)
00384    {
00385       return FALSE;
00386    }
00387 
00388    /*
00389     * The ID register is read/write in a real APIC.
00390     */
00391    reg0 = APICRead(APIC_ID);
00392    DPRINT1("Getting ID: %x\n", reg0);
00393    APICWrite(APIC_ID, reg0 ^ APIC_ID_MASK);
00394    reg1 = APICRead(APIC_ID);
00395    DPRINT1("Getting ID: %x\n", reg1);
00396    APICWrite(APIC_ID, reg0);
00397    if (reg1 != (reg0 ^ APIC_ID_MASK))
00398    {
00399       return FALSE;
00400    }
00401 
00402    MsrValue.QuadPart = __readmsr(0x1B /*MSR_IA32_APICBASE*/);
00403 
00404    if (!(MsrValue.LowPart & /*MSR_IA32_APICBASE_ENABLE*/(1<<11))) 
00405    {
00406       DPRINT1("Local APIC disabled by BIOS -- reenabling.\n");
00407       MsrValue.LowPart &= ~/*MSR_IA32_APICBASE_BASE*/(1<<11);
00408       MsrValue.LowPart |= /*MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE*/(1<<11)|0xfee00000;
00409       __writemsr(0x1B /*MSR_IA32_APICBASE*/, MsrValue.HighPart);
00410    }
00411 
00412     
00413 
00414    return TRUE;
00415 }
00416 
00417 #ifdef CONFIG_SMP
00418 VOID APICSendIPI(ULONG Target, ULONG Mode)
00419 {
00420    ULONG tmp, i, flags;
00421 
00422    /* save flags and disable interrupts */
00423    flags = __readeflags();
00424    _disable();
00425 
00426    /* Wait up to 100ms for the APIC to become ready */
00427    for (i = 0; i < 10000; i++) 
00428    {
00429       tmp = APICRead(APIC_ICR0);
00430       /* Check Delivery Status */
00431       if ((tmp & APIC_ICR0_DS) == 0)
00432          break;
00433       KeStallExecutionProcessor(10);
00434    }
00435 
00436    if (i == 10000) 
00437    {
00438       DPRINT1("CPU(%d) Previous IPI was not delivered after 100ms.\n", ThisCPU());
00439    }
00440 
00441    /* Setup the APIC to deliver the IPI */
00442    DPRINT("%08x %x\n", SET_APIC_DEST_FIELD(Target), Target);
00443    APICWrite(APIC_ICR1, SET_APIC_DEST_FIELD(Target));
00444 
00445    if (Target == APIC_TARGET_SELF) 
00446    {
00447       Mode |= APIC_ICR0_DESTS_SELF;
00448    } 
00449    else if (Target == APIC_TARGET_ALL) 
00450    {
00451       Mode |= APIC_ICR0_DESTS_ALL;
00452    } 
00453    else if (Target == APIC_TARGET_ALL_BUT_SELF) 
00454    {
00455       Mode |= APIC_ICR0_DESTS_ALL_BUT_SELF;
00456    } 
00457    else 
00458    {
00459       Mode |= APIC_ICR0_DESTS_FIELD;
00460    }
00461 
00462    /* Now, fire off the IPI */
00463    APICWrite(APIC_ICR0, Mode);
00464 
00465    /* Wait up to 100ms for the APIC to become ready */
00466    for (i = 0; i < 10000; i++) 
00467    {
00468       tmp = APICRead(APIC_ICR0);
00469       /* Check Delivery Status */
00470       if ((tmp & APIC_ICR0_DS) == 0)
00471          break;
00472       KeStallExecutionProcessor(10);
00473    }
00474 
00475    if (i == 10000) 
00476    {
00477       DPRINT1("CPU(%d) Current IPI was not delivered after 100ms.\n", ThisCPU());
00478    }
00479    __writeeflags(flags);
00480 }
00481 #endif
00482 
00483 VOID APICSetup(VOID)
00484 {
00485    ULONG CPU, tmp;
00486 
00487    CPU = ThisCPU();
00488 
00489 //   APICDump();
00490   
00491    DPRINT1("CPU%d:\n", CPU);
00492    DPRINT1("  Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID)));
00493    DPRINT1("  Logical APIC id:  %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR)));
00494    DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR));
00495 
00496    /*
00497     * Intel recommends to set DFR, LDR and TPR before enabling
00498     * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
00499     * document number 292116).  So here it goes...
00500     */
00501 
00502    /*
00503     * Put the APIC into flat delivery mode.
00504     * Must be "all ones" explicitly for 82489DX.
00505     */
00506    APICWrite(APIC_DFR, 0xFFFFFFFF);
00507 
00508    /*
00509     * Set up the logical destination ID.
00510     */
00511    tmp = APICRead(APIC_LDR);
00512    tmp &= ~APIC_LDR_MASK;
00513    /* 
00514     * FIXME:
00515     *   This works only up to 8 CPU's
00516     */
00517    tmp |= (1 << (KeGetCurrentProcessorNumber() + 24));
00518    APICWrite(APIC_LDR, tmp);
00519 
00520 
00521    DPRINT1("CPU%d:\n", CPU);
00522    DPRINT1("  Physical APIC id: %d\n", GET_APIC_ID(APICRead(APIC_ID)));
00523    DPRINT1("  Logical APIC id:  %d\n", GET_APIC_LOGICAL_ID(APICRead(APIC_LDR)));
00524    DPRINT1("%08x %08x %08x\n", APICRead(APIC_ID), APICRead(APIC_LDR), APICRead(APIC_DFR));
00525    DPRINT1("%d\n", CPUMap[CPU].APICId);
00526 
00527    /* Accept only higher interrupts */
00528    APICWrite(APIC_TPR, 0xef);
00529 
00530    /* Enable local APIC */
00531    tmp = APICRead(APIC_SIVR);
00532    tmp &= ~0xff;
00533    tmp |= APIC_SIVR_ENABLE;
00534 
00535 #if 0
00536    tmp &= ~APIC_SIVR_FOCUS;
00537 #else
00538    tmp |= APIC_SIVR_FOCUS;
00539 #endif
00540 
00541   /* Set spurious interrupt vector */
00542   tmp |= SPURIOUS_VECTOR;
00543   APICWrite(APIC_SIVR, tmp);
00544 
00545   /*
00546    * Set up LVT0, LVT1:
00547    *
00548    * set up through-local-APIC on the BP's LINT0. This is not
00549    * strictly necessery in pure symmetric-IO mode, but sometimes
00550    * we delegate interrupts to the 8259A.
00551    */
00552   tmp = APICRead(APIC_LINT0) & APIC_LVT_MASKED;
00553   if (CPU == BootCPU && (APICMode == amPIC || !tmp)) 
00554   {
00555      tmp = APIC_DM_EXTINT;
00556      DPRINT1("enabled ExtINT on CPU#%d\n", CPU);
00557   } 
00558   else 
00559   {
00560      tmp = APIC_DM_EXTINT | APIC_LVT_MASKED;
00561      DPRINT1("masked ExtINT on CPU#%d\n", CPU);
00562   }
00563   APICWrite(APIC_LINT0, tmp);
00564 
00565   /*
00566    * Only the BSP should see the LINT1 NMI signal, obviously.
00567    */
00568   if (CPU == BootCPU)
00569   {
00570      tmp = APIC_DM_NMI;
00571   }
00572   else
00573   {
00574      tmp = APIC_DM_NMI | APIC_LVT_MASKED;
00575   }
00576   if (!APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 
00577   {
00578      /* 82489DX */
00579      tmp |= APIC_LVT_LEVEL_TRIGGER;
00580   }
00581   APICWrite(APIC_LINT1, tmp);
00582 
00583   if (APIC_INTEGRATED(CPUMap[CPU].APICVersion)) 
00584   { 
00585      /* !82489DX */
00586      if (APICGetMaxLVT() > 3) 
00587      {
00588     /* Due to the Pentium erratum 3AP */
00589     APICWrite(APIC_ESR, 0);
00590      }
00591 
00592      tmp = APICRead(APIC_ESR);
00593      DPRINT("ESR value before enabling vector: 0x%X\n", tmp);
00594 
00595      /* Enable sending errors */
00596      tmp = ERROR_VECTOR;
00597      APICWrite(APIC_LVT3, tmp);
00598 
00599      /*
00600       * Spec says clear errors after enabling vector
00601       */
00602      if (APICGetMaxLVT() > 3)
00603      {
00604         APICWrite(APIC_ESR, 0);
00605      }
00606      tmp = APICRead(APIC_ESR);
00607      DPRINT("ESR value after enabling vector: 0x%X\n", tmp);
00608   }
00609 }
00610 #ifdef CONFIG_SMP
00611 VOID APICSyncArbIDs(VOID)
00612 {
00613    ULONG i, tmp;
00614 
00615    /* Wait up to 100ms for the APIC to become ready */
00616    for (i = 0; i < 10000; i++) 
00617    {
00618       tmp = APICRead(APIC_ICR0);
00619       /* Check Delivery Status */
00620       if ((tmp & APIC_ICR0_DS) == 0)
00621          break;
00622       KeStallExecutionProcessor(10);
00623    }
00624 
00625    if (i == 10000) 
00626    {
00627       DPRINT("CPU(%d) APIC busy for 100ms.\n", ThisCPU());
00628    }
00629 
00630    DPRINT("Synchronizing Arb IDs.\n");
00631    APICWrite(APIC_ICR0, APIC_ICR0_DESTS_ALL | APIC_ICR0_LEVEL | APIC_DM_INIT);
00632 }
00633 #endif
00634 
00635 VOID MpsErrorHandler(VOID)
00636 {
00637   ULONG tmp1, tmp2;
00638 
00639   APICDump();
00640 
00641   tmp1 = APICRead(APIC_ESR);
00642   APICWrite(APIC_ESR, 0);
00643   tmp2 = APICRead(APIC_ESR);
00644   DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
00645 
00646   /*
00647    * Acknowledge the interrupt
00648    */
00649   APICSendEOI();
00650 
00651   /* Here is what the APIC error bits mean:
00652    *   0: Send CS error
00653    *   1: Receive CS error
00654    *   2: Send accept error
00655    *   3: Receive accept error
00656    *   4: Reserved
00657    *   5: Send illegal vector
00658    *   6: Received illegal vector
00659    *   7: Illegal register address
00660    */
00661   DPRINT1("APIC error on CPU(%d) ESR(%x)(%x)\n", ThisCPU(), tmp1, tmp2);
00662   for (;;);
00663 }
00664 
00665 VOID MpsSpuriousHandler(VOID)
00666 {
00667   ULONG tmp;
00668 
00669   DPRINT("Spurious interrupt on CPU(%d)\n", ThisCPU());
00670   
00671   tmp = APICRead(APIC_ISR + ((SPURIOUS_VECTOR & ~0x1f) >> 1));
00672   if (tmp & (1 << (SPURIOUS_VECTOR & 0x1f)))
00673   {
00674       APICSendEOI();
00675       return;
00676   }
00677 #if 0
00678   /* No need to send EOI here */
00679   APICDump();
00680 #endif
00681 }
00682 
00683 #ifdef CONFIG_SMP
00684 VOID MpsIpiHandler(VOID)
00685 {
00686    KIRQL oldIrql;
00687 
00688    HalBeginSystemInterrupt(IPI_LEVEL,
00689                            IPI_VECTOR, 
00690                &oldIrql);
00691    _enable();
00692 #if 0
00693    DbgPrint("(%s:%d) MpsIpiHandler on CPU%d, current irql is %d\n", 
00694             __FILE__,__LINE__, KeGetCurrentProcessorNumber(), KeGetCurrentIrql());
00695 #endif   
00696 
00697    KiIpiServiceRoutine(NULL, NULL);
00698 
00699 #if 0
00700    DbgPrint("(%s:%d) MpsIpiHandler on CPU%d done\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber());
00701 #endif
00702 
00703    _disable();
00704    HalEndSystemInterrupt(oldIrql, 0);
00705 }
00706 #endif
00707 
00708 VOID
00709 MpsIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
00710                PKTRAP_FRAME TrapFrame)
00711 {
00712 #ifdef _M_AMD64
00713     UNIMPLEMENTED;
00714 #else
00715    TrapFrame->SegGs     = (USHORT)IrqTrapFrame->Gs;
00716    TrapFrame->SegFs     = (USHORT)IrqTrapFrame->Fs;
00717    TrapFrame->SegEs     = (USHORT)IrqTrapFrame->Es;
00718    TrapFrame->SegDs     = (USHORT)IrqTrapFrame->Ds;
00719    TrapFrame->Eax    = IrqTrapFrame->Eax;
00720    TrapFrame->Ecx    = IrqTrapFrame->Ecx;
00721    TrapFrame->Edx    = IrqTrapFrame->Edx;
00722    TrapFrame->Ebx    = IrqTrapFrame->Ebx;
00723    TrapFrame->HardwareEsp    = IrqTrapFrame->Esp;
00724    TrapFrame->Ebp    = IrqTrapFrame->Ebp;
00725    TrapFrame->Esi    = IrqTrapFrame->Esi;
00726    TrapFrame->Edi    = IrqTrapFrame->Edi;
00727    TrapFrame->Eip    = IrqTrapFrame->Eip;
00728    TrapFrame->SegCs     = IrqTrapFrame->Cs;
00729    TrapFrame->EFlags = IrqTrapFrame->Eflags;
00730 #endif
00731 }
00732 
00733 VOID
00734 MpsTimerHandler(ULONG Vector, PKIRQ_TRAPFRAME Trapframe)
00735 {
00736    KIRQL oldIrql;
00737    KTRAP_FRAME KernelTrapFrame;
00738 #if 0
00739    ULONG CPU;
00740    static ULONG Count[MAX_CPU] = {0,};
00741 #endif
00742    HalBeginSystemInterrupt(LOCAL_TIMER_VECTOR, 
00743                            PROFILE_LEVEL, 
00744                &oldIrql);
00745    _enable();
00746 
00747 #if 0
00748    CPU = ThisCPU();
00749    if ((Count[CPU] % 100) == 0)
00750    {
00751      DbgPrint("(%s:%d) MpsTimerHandler on CPU%d, irql = %d, epi = %x, KPCR = %x\n", __FILE__, __LINE__, CPU, oldIrql,Trapframe->Eip, KeGetPcr());
00752    }
00753    Count[CPU]++;
00754 #endif
00755 
00756    /* FIXME: SMP is totally broken */
00757    MpsIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
00758    if (KeGetCurrentProcessorNumber() == 0)
00759    {
00760       //KeUpdateSystemTime(&KernelTrapFrame, oldIrql);
00761    }
00762    else
00763    {
00764       //KeUpdateRunTime(&KernelTrapFrame, oldIrql);
00765    }
00766 
00767    _disable();
00768    HalEndSystemInterrupt (oldIrql, 0);
00769 }
00770 
00771 VOID APICSetupLVTT(ULONG ClockTicks)
00772 {
00773    ULONG tmp;
00774 
00775    tmp = GET_APIC_VERSION(APICRead(APIC_VER));
00776    if (!APIC_INTEGRATED(tmp))
00777    {
00778       tmp = SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV) | APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
00779    }
00780    else
00781    {
00782       /* Periodic timer */
00783       tmp = APIC_LVT_PERIODIC | LOCAL_TIMER_VECTOR;
00784    }
00785    APICWrite(APIC_LVTT, tmp);
00786 
00787    tmp = APICRead(APIC_TDCR);
00788    tmp &= ~(APIC_TDCR_1 | APIC_TIMER_BASE_DIV);
00789    tmp |= APIC_TDCR_16;
00790    APICWrite(APIC_TDCR, tmp);
00791    APICWrite(APIC_ICRT, ClockTicks / APIC_DIVISOR);
00792 }
00793 
00794 VOID 
00795 APICCalibrateTimer(ULONG CPU)
00796 {
00797    ULARGE_INTEGER t1, t2;
00798    LONG tt1, tt2;
00799    BOOLEAN TSCPresent;
00800 
00801    DPRINT("Calibrating APIC timer for CPU %d\n", CPU);
00802 
00803    APICSetupLVTT(1000000000);
00804 
00805    TSCPresent = KeGetCurrentPrcb()->FeatureBits & KF_RDTSC ? TRUE : FALSE;
00806 
00807    /*
00808     * The timer chip counts down to zero. Let's wait
00809     * for a wraparound to start exact measurement:
00810     * (the current tick might have been already half done)
00811     */
00812    //WaitFor8254Wraparound();
00813 
00814    /*
00815     * We wrapped around just now. Let's start
00816     */
00817    if (TSCPresent)
00818    {
00819       t1.QuadPart = (LONGLONG)__rdtsc();
00820    }
00821    tt1 = APICRead(APIC_CCRT);
00822 
00823    //WaitFor8254Wraparound();
00824 
00825 
00826    tt2 = APICRead(APIC_CCRT);
00827    if (TSCPresent)
00828    {
00829       t2.QuadPart = (LONGLONG)__rdtsc();
00830       CPUMap[CPU].CoreSpeed = (HZ * (ULONG)(t2.QuadPart - t1.QuadPart));
00831       DPRINT("CPU clock speed is %ld.%04ld MHz.\n",
00832          CPUMap[CPU].CoreSpeed/1000000,
00833          CPUMap[CPU].CoreSpeed%1000000);
00834       KeGetCurrentPrcb()->MHz = CPUMap[CPU].CoreSpeed/1000000;
00835    }
00836 
00837    CPUMap[CPU].BusSpeed = (HZ * (long)(tt1 - tt2) * APIC_DIVISOR);
00838 
00839    /* Setup timer for normal operation */
00840 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100);    // 100ns
00841    APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 10000);  // 10ms
00842 // APICSetupLVTT((CPUMap[CPU].BusSpeed / 1000000) * 100000); // 100ms
00843 
00844    DPRINT("Host bus clock speed is %ld.%04ld MHz.\n",
00845       CPUMap[CPU].BusSpeed/1000000,
00846       CPUMap[CPU].BusSpeed%1000000);
00847 }
00848 
00849 VOID 
00850 SetInterruptGate(ULONG index, ULONG_PTR address)
00851 {
00852 #ifdef _M_AMD64
00853   KIDTENTRY64 *idt;
00854 
00855   idt = &KeGetPcr()->IdtBase[index];
00856 
00857   idt->OffsetLow = address & 0xffff;
00858   idt->Selector = KGDT_64_R0_CODE;
00859   idt->IstIndex = 0;
00860   idt->Reserved0 = 0;
00861   idt->Type = 0x0e;
00862   idt->Dpl = 0;
00863   idt->Present = 1;
00864   idt->OffsetMiddle = (address >> 16) & 0xffff;
00865   idt->OffsetHigh = address >> 32;
00866   idt->Reserved1 = 0;
00867   idt->Alignment = 0;
00868 #else
00869   KIDTENTRY *idt;
00870   KIDT_ACCESS Access;
00871 
00872   /* Set the IDT Access Bits */
00873   Access.Reserved = 0;
00874   Access.Present = 1;
00875   Access.Dpl = 0; /* Kernel-Mode */
00876   Access.SystemSegmentFlag = 0;
00877   Access.SegmentType = I386_INTERRUPT_GATE;
00878   
00879   idt = (KIDTENTRY*)((ULONG)KeGetPcr()->IDT + index * sizeof(KIDTENTRY));
00880   idt->Offset = (USHORT)(address & 0xffff);
00881   idt->Selector = KGDT_R0_CODE;
00882   idt->Access = Access.Value;
00883   idt->ExtendedOffset = (USHORT)(address >> 16);
00884 #endif
00885 }
00886 
00887 VOID HaliInitBSP(VOID)
00888 {
00889 #ifdef CONFIG_SMP
00890    PUSHORT ps;
00891 #endif
00892 
00893    static BOOLEAN BSPInitialized = FALSE;
00894 
00895    /* Only initialize the BSP once */
00896    if (BSPInitialized)
00897    {
00898       ASSERT(FALSE);
00899       return;
00900    }
00901 
00902    BSPInitialized = TRUE;
00903 
00904    /* Setup interrupt handlers */
00905    SetInterruptGate(LOCAL_TIMER_VECTOR, (ULONG_PTR)MpsTimerInterrupt);
00906    SetInterruptGate(ERROR_VECTOR, (ULONG_PTR)MpsErrorInterrupt);
00907    SetInterruptGate(SPURIOUS_VECTOR, (ULONG_PTR)MpsSpuriousInterrupt);
00908 #ifdef CONFIG_SMP
00909    SetInterruptGate(IPI_VECTOR, (ULONG_PTR)MpsIpiInterrupt);
00910 #endif
00911    DPRINT("APIC is mapped at 0x%X\n", APICBase);
00912 
00913    if (VerifyLocalAPIC()) 
00914    {
00915       DPRINT("APIC found\n");
00916    } 
00917    else 
00918    {
00919       DPRINT("No APIC found\n");
00920       ASSERT(FALSE);
00921    }
00922 
00923    if (APICMode == amPIC) 
00924    {
00925       EnableApicMode();
00926    }
00927 
00928    APICSetup();
00929 
00930 #ifdef CONFIG_SMP
00931    /* BIOS data segment */
00932    BIOSBase = (PULONG)BIOS_AREA;
00933    
00934    /* Area for communicating with the APs */
00935    CommonBase = (PULONG)COMMON_AREA;
00936  
00937    /* Copy bootstrap code to common area */
00938    memcpy((PVOID)((ULONG_PTR)CommonBase + PAGE_SIZE),
00939       &APstart,
00940       (ULONG_PTR)&APend - (ULONG_PTR)&APstart + 1);
00941 
00942    /* Set shutdown code */
00943    CMOS_WRITE(0xF, 0xA);
00944 
00945    /* Set warm reset vector */
00946    ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x467);
00947    *ps = (COMMON_AREA + PAGE_SIZE) & 0xF;
00948  
00949    ps = (PUSHORT)((ULONG_PTR)BIOSBase + 0x469);
00950    *ps = (COMMON_AREA + PAGE_SIZE) >> 4;
00951 #endif
00952 
00953    /* Calibrate APIC timer */
00954    APICCalibrateTimer(BootCPU);
00955 }
00956 
00957 #ifdef CONFIG_SMP
00958 VOID
00959 HaliStartApplicationProcessor(ULONG Cpu, ULONG Stack)
00960 {
00961    ULONG tmp, maxlvt;
00962    PCOMMON_AREA_INFO Common;
00963    ULONG StartupCount;
00964    ULONG i, j;
00965    ULONG DeliveryStatus = 0;
00966    ULONG AcceptStatus = 0;
00967 
00968    if (Cpu >= MAX_CPU ||
00969        Cpu >= CPUCount ||
00970        OnlineCPUs & (1 << Cpu))
00971    {
00972      ASSERT(FALSE);
00973    }
00974    DPRINT1("Attempting to boot CPU %d\n", Cpu);
00975 
00976    /* Send INIT IPI */
00977 
00978    APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_ASSERT);
00979  
00980    KeStallExecutionProcessor(200);
00981 
00982    /* Deassert INIT */
00983 
00984    APICSendIPI(Cpu, APIC_DM_INIT|APIC_ICR0_LEVEL_DEASSERT);
00985 
00986    if (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) 
00987    {
00988       /* Clear APIC errors */
00989       APICWrite(APIC_ESR, 0);
00990       tmp = (APICRead(APIC_ESR) & APIC_ESR_MASK);
00991    }
00992 
00993    Common = (PCOMMON_AREA_INFO)CommonBase;
00994 
00995    /* Write the location of the AP stack */
00996    Common->Stack = (ULONG)Stack;
00997    /* Write the page directory page */
00998    Common->PageDirectory = __readcr3();
00999    /* Write the kernel entry point */
01000    Common->NtProcessStartup = (ULONG_PTR)RtlImageNtHeader((PVOID)KernelBase)->OptionalHeader.AddressOfEntryPoint + KernelBase;
01001    /* Write the state of the mae mode */
01002    Common->PaeModeEnabled = __readcr4() & CR4_PAE ? 1 : 0;
01003 
01004    DPRINT1("%x %x %x %x\n", Common->Stack, Common->PageDirectory, Common->NtProcessStartup, Common->PaeModeEnabled);
01005 
01006    DPRINT("Cpu %d got stack at 0x%X\n", Cpu, Common->Stack);
01007 #if 0
01008    for (j = 0; j < 16; j++) 
01009    {
01010       Common->Debug[j] = 0;
01011    }
01012 #endif
01013 
01014    maxlvt = APICGetMaxLVT();
01015 
01016    /* Is this a local APIC or an 82489DX? */
01017    StartupCount = (APIC_INTEGRATED(CPUMap[Cpu].APICVersion)) ? 2 : 0;
01018 
01019    for (i = 1; i <= StartupCount; i++)
01020    {
01021       /* It's a local APIC, so send STARTUP IPI */
01022       DPRINT("Sending startup signal %d\n", i);
01023       /* Clear errors */
01024       APICWrite(APIC_ESR, 0);
01025       APICRead(APIC_ESR);
01026 
01027       APICSendIPI(Cpu, APIC_DM_STARTUP | ((COMMON_AREA + PAGE_SIZE) >> 12)|APIC_ICR0_LEVEL_DEASSERT);
01028 
01029       /* Wait up to 10ms for IPI to be delivered */
01030       j = 0;
01031       do 
01032       {
01033          KeStallExecutionProcessor(10);
01034 
01035          /* Check Delivery Status */
01036          DeliveryStatus = APICRead(APIC_ICR0) & APIC_ICR0_DS;
01037 
01038          j++;
01039       } while ((DeliveryStatus) && (j < 1000));
01040 
01041       KeStallExecutionProcessor(200);
01042 
01043       /*
01044        * Due to the Pentium erratum 3AP.
01045        */
01046       if (maxlvt > 3) 
01047       {
01048         APICRead(APIC_SIVR);
01049         APICWrite(APIC_ESR, 0);
01050       }
01051 
01052       AcceptStatus = APICRead(APIC_ESR) & APIC_ESR_MASK;
01053 
01054       if (DeliveryStatus || AcceptStatus) 
01055       {
01056          break;
01057       }
01058    }
01059 
01060    if (DeliveryStatus) 
01061    {
01062       DPRINT("STARTUP IPI for CPU %d was never delivered.\n", Cpu);
01063    }
01064 
01065    if (AcceptStatus) 
01066    {
01067       DPRINT("STARTUP IPI for CPU %d was never accepted.\n", Cpu);
01068    }
01069 
01070    if (!(DeliveryStatus || AcceptStatus)) 
01071    {
01072 
01073       /* Wait no more than 5 seconds for processor to boot */
01074       DPRINT("Waiting for 5 seconds for CPU %d to boot\n", Cpu);
01075 
01076       /* Wait no more than 5 seconds */
01077       for (j = 0; j < 50000; j++) 
01078       {
01079          if (CPUMap[Cpu].Flags & CPU_ENABLED)
01080      {
01081             break;
01082      }
01083          KeStallExecutionProcessor(100);
01084       }
01085    }
01086 
01087    if (CPUMap[Cpu].Flags & CPU_ENABLED) 
01088    {
01089       DbgPrint("CPU %d is now running\n", Cpu);
01090    } 
01091    else 
01092    {
01093       DbgPrint("Initialization of CPU %d failed\n", Cpu);
01094    }
01095 
01096 #if 0
01097    DPRINT("Debug bytes are:\n");
01098 
01099    for (j = 0; j < 4; j++) 
01100    {
01101       DPRINT("0x%08X 0x%08X 0x%08X 0x%08X.\n",
01102              Common->Debug[j*4+0],
01103              Common->Debug[j*4+1],
01104              Common->Debug[j*4+2],
01105              Common->Debug[j*4+3]);
01106    }
01107 
01108 #endif
01109 }
01110 
01111 #endif
01112 
01113 VOID
01114 FASTCALL
01115 DECLSPEC_NORETURN
01116 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
01117 {
01118     /* Set up a fake INT Stack */
01119     TrapFrame->EFlags = __readeflags();
01120     TrapFrame->SegCs = KGDT_R0_CODE;
01121     TrapFrame->Eip = TrapFrame->Eax;
01122     
01123     /* Build the trap frame */
01124     KiEnterInterruptTrap(TrapFrame);
01125     
01126     /* unimplemented */
01127     UNIMPLEMENTED;
01128     
01129     /* Exit the interrupt */
01130     KiEoiHelper(TrapFrame); 
01131 
01132 }
01133 
01134 /* EOF */

Generated on Fri May 25 2012 04:26:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.