First public contribution.
1 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // wins\specific\variant.cpp
20 #include <kernel/kern_priv.h>
25 const TInt KDefaultRam = 63; // 63MB default internal RAM
26 const TInt KUnlimitedRam = 0x400; // 1GB ~= unlimited memory
27 const TInt KDefaultRamDrive = 0x400000; // 4MB default RAM drive limit
29 _LIT(KLitWins,"Wins");
31 GLDEF_D Wins TheVariant;
33 GLDEF_D TActualMachineConfig TheConfig;
35 EXPORT_C Asic* VariantInitialise(TBool aRunExe)
37 return TheVariant.Init(aRunExe) == KErrNone ? &TheVariant : NULL;
44 class DWinsPowerController : public DPowerController
46 public: // from DPowerComtroller
48 void EnableWakeupEvents();
49 void AbsoluteTimerExpired();
50 void DisableWakeupEvents();
51 void PowerDown(TTimeK aWakeupTime);
53 static DWinsPowerController* New();
54 void AssertWakeupSignal();
63 :iUi(0), iRealCpuSpeed(0), iCpuSpeed(0),
64 iDebugOutput(INVALID_HANDLE_VALUE), iLogTimeStamp(ETrue),
65 iPurgedImages(EFalse), iPowerController(0), iLogToDebugger(EFalse),
69 TInt Wins::Init(TBool aRunExe)
71 TInt r = InitProperties(aRunExe);
74 iProperties.GetInt("LogTimeStamp",iLogTimeStamp);
75 TInt logThreadId=ETrue;
76 iProperties.GetInt("LogThreadId",logThreadId);
77 TInt cpu=NThread::ECpuSingle;
78 iProperties.GetInt("HostCPU",cpu);
79 NThread::SetProperties(logThreadId,cpu);
80 iProperties.GetInt("LogToDebugger",iLogToDebugger);
81 iProperties.GetInt("LogToFile",iLogToFile);
84 Kern::SuperPage().iDebugMask[0] = DebugMask(); // get int or text mask value
85 // check to see if DebugMask0 was used instead of DebugMask
86 if ( (iProperties.GetInt("DebugMask", mask) != KErrNone) &&
87 (iProperties.GetInt("DebugMask0", mask) == KErrNone) )
88 Kern::SuperPage().iDebugMask[0] = ((iProperties.GetInt("DebugMask0", mask) == KErrNone) ? mask : 0);
90 // only int entries are supported for DebugMasks 1-7
91 Kern::SuperPage().iDebugMask[1] = ((iProperties.GetInt("DebugMask1", mask) == KErrNone) ? mask : 0);
92 Kern::SuperPage().iDebugMask[2] = ((iProperties.GetInt("DebugMask2", mask) == KErrNone) ? mask : 0);
93 Kern::SuperPage().iDebugMask[3] = ((iProperties.GetInt("DebugMask3", mask) == KErrNone) ? mask : 0);
94 Kern::SuperPage().iDebugMask[4] = ((iProperties.GetInt("DebugMask4", mask) == KErrNone) ? mask : 0);
95 Kern::SuperPage().iDebugMask[5] = ((iProperties.GetInt("DebugMask5", mask) == KErrNone) ? mask : 0);
96 Kern::SuperPage().iDebugMask[6] = ((iProperties.GetInt("DebugMask6", mask) == KErrNone) ? mask : 0);
97 Kern::SuperPage().iDebugMask[7] = ((iProperties.GetInt("DebugMask7", mask) == KErrNone) ? mask : 0);
99 // initial values for fast trace...
100 Kern::SuperPage().iInitialBTraceFilter[0] = ((iProperties.GetInt("BTrace0", mask) == KErrNone) ? mask : 0);
101 Kern::SuperPage().iInitialBTraceFilter[1] = ((iProperties.GetInt("BTrace1", mask) == KErrNone) ? mask : 0);
102 Kern::SuperPage().iInitialBTraceFilter[2] = ((iProperties.GetInt("BTrace2", mask) == KErrNone) ? mask : 0);
103 Kern::SuperPage().iInitialBTraceFilter[3] = ((iProperties.GetInt("BTrace3", mask) == KErrNone) ? mask : 0);
104 Kern::SuperPage().iInitialBTraceFilter[4] = ((iProperties.GetInt("BTrace4", mask) == KErrNone) ? mask : 0);
105 Kern::SuperPage().iInitialBTraceFilter[5] = ((iProperties.GetInt("BTrace5", mask) == KErrNone) ? mask : 0);
106 Kern::SuperPage().iInitialBTraceFilter[6] = ((iProperties.GetInt("BTrace6", mask) == KErrNone) ? mask : 0);
107 Kern::SuperPage().iInitialBTraceFilter[7] = ((iProperties.GetInt("BTrace7", mask) == KErrNone) ? mask : 0);
108 Kern::SuperPage().iInitialBTraceBuffer = ((iProperties.GetInt("BTraceBuffer", mask) == KErrNone) ? mask : 0);
109 Kern::SuperPage().iInitialBTraceMode = ((iProperties.GetInt("BTraceMode", mask) == KErrNone) ? mask : 0);
111 Kern::SuperPage().SetKernelConfigFlags(KernelConfigFlags());
114 DisabledCapabilities(caps);
115 memcpy(&Kern::SuperPage().iDisabledCapabilities,&caps,sizeof(caps));
121 inline void Wins::InstallUi(DWinsUiBase& aUi)
126 __KTRACE_OPT(KBOOT,Kern::Printf("Wins::Init1()"));
128 TInt tickperiod = WinsTimer::EDefaultPeriod;
129 iProperties.GetInt("TimerResolution",tickperiod);
130 iTimer.Init(tickperiod);
132 if (iProperties.GetInt("CPUSpeed", (TInt&)speed) == KErrNone)
136 static TInt emulatorHal(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
138 return ((Wins*)aPtr)->EmulatorHal(aFunction, a1, a2);
143 // Initialise timer tick and add emulator hal function
146 __KTRACE_OPT(KBOOT,Kern::Printf("Wins::Init3()"));
148 Kern::AddHalEntry(EHalGroupEmulator,&emulatorHal,this);
150 iPowerController = DWinsPowerController::New();
151 if (iPowerController == 0)
152 __PM_PANIC("Can't create 'DWinsPowerController'");
157 void Wins::AddressInfo(SAddressInfo& aInfo)
159 TInt megabytes = KDefaultRam;
160 iProperties.GetInt("MegabytesOfFreeMemory", megabytes);
162 megabytes = KUnlimitedRam;
163 aInfo.iTotalRamSize = megabytes << 20;
165 TInt ramdisk = KDefaultRamDrive;
166 iProperties.GetInt("RamDriveMaxSize", ramdisk);
167 aInfo.iRamDriveMaxSize = ramdisk;
170 void Wins::PurgeImages()
172 // Use the idle thread to clean up remnants of the emulator from the image path
175 char path[KMaxFileName+1];
177 const char* imgPath=0;
178 iProperties.GetString("EmulatorImagePath", imgPath);
179 strcpy(path, imgPath);
180 char* name = path +strlen(path);
185 WIN32_FIND_DATAA fdata;
186 HANDLE finder = FindFirstFileA(path, &fdata);
187 if (finder != INVALID_HANDLE_VALUE)
191 if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
193 strcpy(name, fdata.cFileName);
196 } while (FindNextFileA(finder, &fdata));
205 // Use the win32 NKern idle function
208 iTimer.SetIdleThread();
212 iPurgedImages = ETrue;
217 TInt Wins::MsTickPeriod()
219 // Provide the 'millisecond' timer tick period in microseconds
222 return 1000 * iTimer.Period();
225 TInt Wins::SystemTimeInSecondsFrom2000(TInt& aTime)
227 aTime = iTimer.SystemTime();
228 __KTRACE_OPT(KHARDWARE,Kern::Printf("RTC READ: %d",aTime));
232 TInt Wins::SetSystemTimeInSecondsFrom2000(TInt aTime)
234 // Set the emulator time. We must not change the Win32 time so
235 // we just adjust the offset value to account for the difference
238 __KTRACE_OPT(KHARDWARE,Kern::Printf("Set RTC: %d",aTime));
239 iTimer.SetSystemTime(aTime);
243 TInt Wins::VariantHal(TInt aFunction, TAny* a1, TAny* /*a2*/)
248 case EVariantHalVariantInfo:
250 TVariantInfoV01Buf infoBuf;
251 TVariantInfoV01& info=infoBuf();
253 // info.iRomVersion=TVersion(KRomMajorVersionNumber,KRomMinorVersionNumber,KRomBuildVersionNumber);
254 info.iMachineUniqueId=0;
255 info.iLedCapabilities=0x0;
256 info.iProcessorClockInKHz=iCpuSpeed ? iCpuSpeed*1000 : 1;
261 Kern::InfoCopy(*(TDes8*)a1,infoBuf);
265 case EVariantHalCustomRestartReason:
267 //This will take value from c:\data\epoc.ini.
268 TInt x = Property::GetInt("CustomRestartReason");
269 kumemput32(a1, &x, sizeof(TInt));
273 case EVariantHalCustomRestart:
275 if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EVariantHalCustomRestart")))
276 return KErrPermissionDenied;
277 //This will only shut down epoc as Custom Restart Reason is not supported on wins.
278 Kern::Restart((TInt)a1);
289 TPtr8 Wins::MachineConfiguration()
291 return TPckg<TActualMachineConfig>(TheConfig);
294 void Wins::CalibrateCpuSpeed()
296 // calculate approx. CPU speed in MHz, 0 if we can't tell
299 TInt cycleCount =200*1000*20; //take 20ms at 20MHz
301 // This loop will double the cyclecount until the difference is non-zero.
304 if (cycleCount > (KMaxTUint / 2))
309 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
311 if (QueryPerformanceCounter(&start))
313 __asm mov eax, cycleCount
367 QueryPerformanceCounter(&end);
369 QueryPerformanceFrequency(&f);
371 TInt64 diff = (end.QuadPart - start.QuadPart);
374 TInt64 hz = (TInt64(cycleCount) / 1000000) * (f.QuadPart / diff);
375 iRealCpuSpeed = (TUint)(hz);
379 cycleCount *= 2; // Double the count!!
382 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
385 TInt Wins::SetCpuSpeed(TUint aSpeed)
387 if (iRealCpuSpeed == 0)
388 return KErrNotSupported; // don't know the real CPUSpeed
390 if (IsDebuggerPresent())
391 return KErrGeneral; // nobbling not avaliable when debugging
394 aSpeed = iRealCpuSpeed; // reset to maximum
395 else if (aSpeed > iRealCpuSpeed)
396 aSpeed = iRealCpuSpeed;
397 else if (aSpeed * 20u < iRealCpuSpeed)
398 aSpeed = (iRealCpuSpeed + 19u) / 20u;
400 __KTRACE_OPT(KHARDWARE,Kern::Printf("Set CPUSpeed: %d",aSpeed));
403 // calculate CPU time to nobble in parts-per-million
404 TUint nobble = ((iRealCpuSpeed - aSpeed) * 1000000u) / iRealCpuSpeed;
405 iTimer.Nobble(nobble);
409 HANDLE Wins::DebugOutput()
411 // Return a handle to the trace file, creating the file if required.
413 // The log file name can be specified by a property or environment
414 // variable called 'EmulatorLog', otherwise it defaults to
415 // 'epocwind.out' in the temporary directory.
418 HANDLE file = iDebugOutput;
419 if (file == INVALID_HANDLE_VALUE)
421 CHAR debugfile[MAX_PATH];
423 if (iProperties.GetString("EmulatorLog",logpath)==KErrNone)
424 strcpy(debugfile,logpath);
427 DWORD len = GetEnvironmentVariableA("EmulatorLog", debugfile, MAX_PATH);
431 len=GetTempPathA(MAX_PATH,debugfile);
432 strcpy(debugfile+len,"epocwind.out"); // EPOC WINS DEBUG output file
435 file=CreateFileA(debugfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
436 if (file!=INVALID_HANDLE_VALUE)
438 SetFilePointer(file, NULL, NULL, FILE_END);
445 const TInt MaxOutputMsg = 599;
447 void Wins::EarlyLogging(const char* aMessage1,const char* aMessage2)
449 char message[MaxOutputMsg+3];
450 TInt len = min(strlen(aMessage1), MaxOutputMsg);
451 memcpy(message,aMessage1,len);
454 TInt len2 = min((TInt)strlen(aMessage2), MaxOutputMsg-len);
455 memcpy(message+len,aMessage2,len2);
458 message[len++] = '\r';
459 message[len++] = '\n';
465 WriteFile(DebugOutput(), message, len, &bytes, NULL);
469 OutputDebugStringA(message);
473 void Wins::DebugPrint(const TDesC8& aDes)
475 // Send the string to the debug output (Win32 debug trace) and trace file
478 char message[MaxOutputMsg+1];
479 TInt len = aDes.Length();
480 const char* ptr = (const char*)aDes.Ptr();
484 _ultoa(NKern::TickCount() * iTimer.Period(), message + 10, 10);
485 int n = strlen(message);
486 len = min(len, MaxOutputMsg - n - 2);
487 char* msg = message + n;
489 msg[-1] = n < 10+2 ? '0' : msg[-2];
490 msg[-2] = n < 10+3 ? '0' : msg[-3];
496 strncpy(msg, ptr, len);
503 len = min(len, MaxOutputMsg);
504 strncpy(message, ptr, len);
508 TInt irq = NKern::DisableAllInterrupts();
512 WriteFile(DebugOutput(), ptr, len, &bytes, NULL);
516 OutputDebugStringA(message);
519 NKern::RestoreInterrupts(irq);
522 const char* const KErrorTitles[] =
524 "Symbian OS Fatal Error",
525 "Symbian OS Application Error"
528 const TText8* const KErrorMsg[] =
530 _S8("An error has been detected in the Symbian OS emulator."),
531 _S8("A call to User::Panic() has occured, indicating\n"
532 "a programming fault in the running application.\n"
533 "Please refer to the documentation for more details.")
536 _LIT8(KProgram, "\n\nProgram\t");
537 _LIT8(KError, "\nError\t");
538 _LIT8(KIDFC, "an IDFC");
539 _LIT8(KEscaped, "an escaped thread");
540 _LIT8(KInterrupt, "an interrupt thread");
541 _LIT8(KNThread, "an NThread");
542 _LIT8(KColon, " : ");
543 _LIT8(KDebugQuery, "\n\nDo you wish to Debug the error?\0");
545 TBool Wins::ErrorDialog(TError aType, const TDesC8& aPanic, TInt aVal)
547 // Must be called with interrupts enabled to allow thread running windows message loop to run
549 TBuf8<512> message(KErrorMsg[aType]);
550 message.Append(KProgram);
551 TInt context = NKern::CurrentContext();
555 message.Append(KIDFC);
557 case NKern::EEscaped:
558 message.Append(KEscaped);
560 case NKern::EInterrupt:
561 message.Append(KInterrupt);
564 DThread *thread = Kern::NThreadToDThread(NKern::CurrentThread());
566 thread->TraceAppendFullName(message, ETrue);
568 message.Append(KNThread);
571 message.Append(KError);
572 message.Append(aPanic);
573 message.Append(KColon);
574 message.AppendNum(aVal);
576 message.Append(KDebugQuery);
577 UINT type = MB_YESNO | MB_DEFBUTTON2;
581 type |= MB_SETFOREGROUND | MB_ICONERROR;
582 message.Append('\0');
584 TInt r = MessageBoxA(iUi ? iUi->HWnd() : NULL, (LPCSTR)message.Ptr(), KErrorTitles[aType], type);
590 EXPORT_C DWinsUiBase::DWinsUiBase()
592 TheVariant.InstallUi(*this);
596 TInt BinaryPowerInit();
598 DWinsPowerController* DWinsPowerController::New()
600 DWinsPowerController* self = new DWinsPowerController();
603 self->iStandbySem = CreateSemaphore(NULL, 0, 1, NULL);
604 if (self->iStandbySem == NULL)
606 TInt r = BinaryPowerInit();
613 void DWinsPowerController::CpuIdle()
615 Arch::TheAsic()->Idle();
618 void DWinsPowerController::EnableWakeupEvents()
620 iWakeupSignal = EFalse;
623 void DWinsPowerController::DisableWakeupEvents()
627 void DWinsPowerController::AbsoluteTimerExpired()
629 if (iTargetState == EPwStandby)
630 DWinsPowerController::WakeupEvent();
633 void DWinsPowerController::WakeupEvent()
635 if (iTargetState == EPwStandby)
637 iWakeupSignal = ETrue;
638 DPowerController::WakeupEvent();
642 // called in Epoc thread
643 void DWinsPowerController::PowerDown(TTimeK aWakeupTime)
645 if (iTargetState == EPwStandby)
648 if (aWakeupTime == 0)
649 timeoutMs = INFINITE;
652 TTimeK now = Kern::SystemTime();
653 if (now > aWakeupTime)
656 timeoutMs = (UINT)((aWakeupTime - now) / 1000);
658 TInt l = NKern::DisableAllInterrupts();
659 if (!iWakeupSignal && timeoutMs)
662 TheVariant.iTimer.Standby();
663 NKern::RestoreInterrupts(l);
664 DWORD r = WaitForSingleObject(iStandbySem, timeoutMs);
665 if (r == WAIT_TIMEOUT)
667 l = NKern::DisableAllInterrupts();
669 WaitForSingleObject(iStandbySem, INFINITE);
672 NKern::RestoreInterrupts(l);
674 TheVariant.iTimer.Wakeup();
677 NKern::RestoreInterrupts(l);
681 Kern::Restart(0x80000000);
684 // called in the interrupt context
685 void DWinsPowerController::AssertWakeupSignal()
687 iWakeupSignal = ETrue;
691 ReleaseSemaphore(iStandbySem, 1, NULL);
696 EXPORT_C void Wins::AssertWakeupSignal()
698 iPowerController->AssertWakeupSignal();
701 EXPORT_C void Wins::WakeupEvent()
703 iPowerController->DWinsPowerController::WakeupEvent();
706 // MMC emulation support
708 TBool Wins::MediaDoorOpen;
709 TInt Wins::CurrentPBusDevice;
710 TAny* Wins::MediaChangeCallbackParam;
711 TMediaChangeCallBack Wins::MediaChangeCallBackPtr;
714 EXPORT_C TBool* Wins::MediaDoorOpenPtr()
716 // For media change simulation
720 return(&MediaDoorOpen);
723 EXPORT_C TInt* Wins::CurrentPBusDevicePtr()
725 // For media change simulation
729 return(&CurrentPBusDevice);
732 EXPORT_C void Wins::SetMediaChangeCallBackPtr(TMediaChangeCallBack aPtr, TAny* aMediaChangeCallbackParam)
734 // For media change simulation
737 MediaChangeCallbackParam=aMediaChangeCallbackParam;
738 MediaChangeCallBackPtr=aPtr;
741 EXPORT_C void Wins::MediaChangeCallBack()
743 // Perform the simulated media change callback
746 if(MediaChangeCallBackPtr)
747 (*MediaChangeCallBackPtr)(MediaChangeCallbackParam);