diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kernel/eka/nkernsmp/x86/nccpu.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kernel/eka/nkernsmp/x86/nccpu.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,226 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\nkernsmp\x86\nccpu.cpp +// +// + +#include +#include + + +const TLinAddr KWarmResetTrampolineAddr = 0x467; + +TLinAddr ApTrampolinePage = 0; // overridden in multiple memory model with linear address + +extern "C" void nanowait(TUint32 aNanoseconds); +void cmos_write(TUint32 val, TUint32 addr); +void SetupApInitInfo(volatile SApInitInfo&); +void _ApMain(); + +TInt WakeAP(TInt aAPICID) + { + __KTRACE_OPT(KBOOT,DEBUGPRINT("WakeAP %d", aAPICID)); + read_apic_reg(SIVR); + write_apic_reg(ESR, 0); + read_apic_reg(ESR); + + __KTRACE_OPT(KBOOT,DEBUGPRINT("Asserting INIT")); + + //Turn INIT on target chip + write_apic_reg(ICRH, aAPICID<<24); + + // Send IPI + write_apic_reg(ICRL, 0xC500); + + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); + TInt timeout = 0; + TUint32 send_status; + TUint32 accept_status; + do { + __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); + nanowait(100000); + send_status = read_apic_reg(ICRL) & 0x1000; + } while (send_status && (++timeout < 1000)); + + nanowait(10000000); + + __KTRACE_OPT(KBOOT,DEBUGPRINT("Deasserting INIT")); + + // Target chip + write_apic_reg(ICRH, aAPICID<<24); + + // Send IPI + write_apic_reg(ICRL, 0x8500); + + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); + timeout = 0; + do { + __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); + nanowait(100000); + send_status = read_apic_reg(ICRL) & 0x1000; + } while (send_status && (++timeout < 1000)); + + /* + * Should we send STARTUP IPIs ? + * + * Determine this based on the APIC version. + * If we don't have an integrated APIC, don't send the STARTUP IPIs. + */ +// if (APIC_INTEGRATED(apic_version[phys_apicid])) + TInt num_starts = 2; +// else +// num_starts = 0; + + // Run STARTUP IPI loop. +// maxlvt = get_maxlvt(); + + TInt j; + for (j = 1; j <= num_starts; j++) + { + __KTRACE_OPT(KBOOT,DEBUGPRINT("Sending STARTUP %d",j)); + read_apic_reg(SIVR); + write_apic_reg(ESR, 0); + read_apic_reg(ESR); + + // target chip + write_apic_reg(ICRH, aAPICID<<24); + + // send startup IPI + write_apic_reg(ICRL, (0x600 | (KApBootPage>>12))); + + // give other CPU time to accept it + nanowait(300000); + + __KTRACE_OPT(KBOOT,DEBUGPRINT("Waiting for send to finish...")); + timeout = 0; + do { + __KTRACE_OPT(KBOOT,DEBUGPRINT("+")); + nanowait(100000); + send_status = read_apic_reg(ICRL) & 0x1000; + } while (send_status && (++timeout < 1000)); + + // give other CPU time to accept it + nanowait(300000); + + /* + * Due to the Pentium erratum 3AP. + */ +// if (maxlvt > 3) { +// read_apic_reg(APIC_SPIV); +// write_apic_reg(APIC_ESR, 0); +// } + accept_status = (read_apic_reg(ESR) & 0xEF); + if (send_status || accept_status) + break; + } + __KTRACE_OPT(KBOOT,DEBUGPRINT("After startup")); + + if (send_status) + __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC never delivered???")); + if (accept_status) + __KTRACE_OPT(KBOOT,DEBUGPRINT("APIC delivery error %x", accept_status)); + + return (send_status | accept_status); + } + + + +TInt NKern::BootAP(volatile SAPBootInfo* aInfo) + { + __KTRACE_OPT(KBOOT,DEBUGPRINT("NKern::BootAP %08x %08x+%x", aInfo->iCpu, aInfo->iInitStackBase, aInfo->iInitStackSize)); + + cmos_write(0xa, 0xf); + + TUint8* t = (TUint8*)(KWarmResetTrampolineAddr + ApTrampolinePage); + TUint cs = KApBootPage>>4; + *t++ = 0; // IP low + *t++ = 0; // IP high + *t++ = (TUint8)cs; + *t++ = cs>>8; + + volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage; + TCpuPages& cp=X86::CpuPage(); + SetupApInitInfo(a); + memcpy((TAny*)a.iTempGdt, cp.iGdt, sizeof(cp.iGdt)); + a.iTempGdtr = TUint64(KApBootPage + _FOFF(SApInitInfo,iTempGdt))<<16 | TUint64(KSmpGdtSize*sizeof(SX86Des)-1); + a.iRgs.iCs = RING0_CS; + a.iRgs.iEip = (TLinAddr)&_ApMain; + a.iBootFlag = 0; + a.iBootFlag2 = 0; + a.iLinAddr = (TLinAddr)&a; + + a.iStackBase = aInfo->iInitStackBase; + a.iStackSize = aInfo->iInitStackSize; + a.iRgs.iEsp = a.iStackBase + a.iStackSize; + a.iExtra = (TAny*)aInfo; + + TInt r = WakeAP(aInfo->iCpu); + if (r!=0) + return KErrGeneral; + + TInt timeout = 500; + while (--timeout) + { + nanowait(1000000); + if (a.iBootFlag == KBootFlagMagic-1) + break; + __chill(); + } + __KTRACE_OPT(KBOOT, DEBUGPRINT("iBootFlag=%08x",a.iBootFlag)); + if (timeout==0) + return KErrTimedOut; + + __e32_atomic_add_ord32(&a.iBootFlag, TUint32(-1)); + + NKern::DisableAllInterrupts(); + while (a.iBootFlag2==0) + {} + __e32_io_completion_barrier(); + a.iBootFlag2 = 2; + __e32_io_completion_barrier(); + a.iBPTimestamp = X86::Timestamp(); + __e32_io_completion_barrier(); + while (a.iBootFlag2==2) + {} + __e32_io_completion_barrier(); + NKern::EnableAllInterrupts(); + + return KErrNone; + } + +void InitAPTimestamp(SNThreadCreateInfo&) + { + volatile SApInitInfo& a = *(volatile SApInitInfo*)KApBootPage; + NKern::DisableAllInterrupts(); + a.iBootFlag2 = 1; + __e32_io_completion_barrier(); + while (a.iBootFlag2==1) + {} + __e32_io_completion_barrier(); + a.iAPTimestamp = X86::Timestamp(); + __e32_io_completion_barrier(); + TUint64 bpt = a.iBPTimestamp; + TUint64 apt = a.iAPTimestamp; + TUint64 delta = bpt - apt; + TSubScheduler& ss = SubScheduler(); + ss.iLastTimestamp64 += delta; + *(TUint64*)&ss.i_TimestampOffset = delta; + __KTRACE_OPT(KBOOT,DEBUGPRINT("APT=0x%lx BPT=0x%lx Delta=0x%lx", apt, bpt, delta)); + __e32_io_completion_barrier(); + a.iBootFlag2 = 3; + NKern::EnableAllInterrupts(); + } + + +