thread-r0drv-nt.cpp revision 41c15aa44c4acfe6760552150eb931319835cfaf
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/* $Id$ */
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/** @file
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * IPRT - Threads, Ring-0 Driver, NT.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync */
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/*
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync *
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * available from http://www.virtualbox.org. This file is free software;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * General Public License (GPL) as published by the Free Software
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync *
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * The contents of this file may alternatively be used under the terms
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * of the Common Development and Distribution License Version 1.0
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * VirtualBox OSE distribution, in which case the provisions of the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * CDDL are applicable instead of those of the GPL.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync *
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * You may elect to license modified versions of this file under the
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * terms and conditions of either the GPL or the CDDL or both.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync *
df3d4c8e9c81584c535676a3d40c57d868ac61bbvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * additional information or have any questions.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync */
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync/*******************************************************************************
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync* Header Files *
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync*******************************************************************************/
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include "the-nt-kernel.h"
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include "internal/iprt.h"
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include <iprt/thread.h>
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include <iprt/asm.h>
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include <iprt/assert.h>
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include <iprt/err.h>
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include <iprt/mp.h>
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync#include "internal-r0drv-nt.h"
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
df3d4c8e9c81584c535676a3d40c57d868ac61bbvboxsyncRT_C_DECLS_BEGIN
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncNTSTATUS NTAPI ZwYieldExecution(void);
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncRT_C_DECLS_END
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncRTDECL(RTNATIVETHREAD) RTThreadNativeSelf(void)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync{
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return (RTNATIVETHREAD)PsGetCurrentThread();
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync}
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
f902ede7eb073d09a81c1d470c089c7b14921714vboxsync
97674677e4f2aeae576c39f966568dd664ba7979vboxsyncRTDECL(int) RTThreadSleep(unsigned cMillies)
18673eee0624b4581d3d56ab9ad9d10ebc7f5bddvboxsync{
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync LARGE_INTEGER Interval;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync Interval.QuadPart = -(int64_t)cMillies * 10000;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync NTSTATUS rcNt = KeDelayExecutionThread(KernelMode, TRUE, &Interval);
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync switch (rcNt)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync {
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync case STATUS_SUCCESS:
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return VINF_SUCCESS;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync case STATUS_ALERTED:
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync case STATUS_USER_APC:
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return VERR_INTERRUPTED;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync default:
f6cc81e94c29cc9b39b896cf32ecfe0501b4a1e5vboxsync return RTErrConvertFromNtStatus(rcNt);
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync }
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync}
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncRTDECL(bool) RTThreadYield(void)
f6cc81e94c29cc9b39b896cf32ecfe0501b4a1e5vboxsync{
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return ZwYieldExecution() != STATUS_NO_YIELD_PERFORMED;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync}
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncRTDECL(bool) RTThreadPreemptIsEnabled(RTTHREAD hThread)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync{
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync Assert(hThread == NIL_RTTHREAD);
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync KIRQL Irql = KeGetCurrentIrql();
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync if (Irql > APC_LEVEL)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return false;
9ced981a0263f6280ccbf5dc64c0e81fbe4a2fdavboxsync if (!ASMIntAreEnabled())
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return false;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return true;
f902ede7eb073d09a81c1d470c089c7b14921714vboxsync}
97674677e4f2aeae576c39f966568dd664ba7979vboxsync
18673eee0624b4581d3d56ab9ad9d10ebc7f5bddvboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsyncRTDECL(bool) RTThreadPreemptIsPending(RTTHREAD hThread)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync{
f902ede7eb073d09a81c1d470c089c7b14921714vboxsync Assert(hThread == NIL_RTTHREAD);
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync /*
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Read the globals and check if they are useful.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync */
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync uint32_t const offQuantumEnd = g_offrtNtPbQuantumEnd;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync uint32_t const cbQuantumEnd = g_cbrtNtPbQuantumEnd;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync uint32_t const offDpcQueueDepth = g_offrtNtPbDpcQueueDepth;
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync if (!offQuantumEnd && !cbQuantumEnd && !offDpcQueueDepth)
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync return false;
f6cc81e94c29cc9b39b896cf32ecfe0501b4a1e5vboxsync Assert((offQuantumEnd && cbQuantumEnd) || (!offQuantumEnd && !cbQuantumEnd));
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync
84bebd094718692856715fb7ed9e592c9421e039vboxsync /*
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync * Disable interrupts so we won't be messed around.
7bff28e0cedd8656acd24b420759649184d8cf00vboxsync */
bool fPending;
RTCCUINTREG fSavedFlags = ASMIntDisableFlags();
#ifdef RT_ARCH_X86
PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr));
uint8_t *pbPrcb = (uint8_t *)pPcr->Prcb;
#elif defined(RT_ARCH_AMD64)
/* HACK ALERT! The offset is from windbg/vista64. */
PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self));
uint8_t *pbPrcb = (uint8_t *)pPcr->CurrentPrcb;
#else
# error "port me"
#endif
/* Check QuantumEnd. */
if (cbQuantumEnd == 1)
{
uint8_t volatile *pbQuantumEnd = (uint8_t volatile *)(pbPrcb + offQuantumEnd);
fPending = *pbQuantumEnd == TRUE;
}
else if (cbQuantumEnd == sizeof(uint32_t))
{
uint32_t volatile *pu32QuantumEnd = (uint32_t volatile *)(pbPrcb + offQuantumEnd);
fPending = *pu32QuantumEnd != 0;
}
/* Check DpcQueueDepth. */
if ( !fPending
&& offDpcQueueDepth)
{
uint32_t volatile *pu32DpcQueueDepth = (uint32_t volatile *)(pbPrcb + offDpcQueueDepth);
fPending = *pu32DpcQueueDepth > 0;
}
ASMSetFlags(fSavedFlags);
return fPending;
}
RTDECL(bool) RTThreadPreemptIsPendingTrusty(void)
{
/* RTThreadPreemptIsPending is only reliable of we've got both offsets and size. */
return g_offrtNtPbQuantumEnd != 0
&& g_cbrtNtPbQuantumEnd != 0
&& g_offrtNtPbDpcQueueDepth != 0;
}
RTDECL(bool) RTThreadPreemptIsPossible(void)
{
/* yes, kernel preemption is possible. */
return true;
}
RTDECL(void) RTThreadPreemptDisable(PRTTHREADPREEMPTSTATE pState)
{
AssertPtr(pState);
Assert(pState->uchOldIrql == 255);
Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
KeRaiseIrql(DISPATCH_LEVEL, &pState->uchOldIrql);
RT_ASSERT_PREEMPT_CPUID_DISABLE(pState);
}
RTDECL(void) RTThreadPreemptRestore(PRTTHREADPREEMPTSTATE pState)
{
AssertPtr(pState);
RT_ASSERT_PREEMPT_CPUID_RESTORE(pState);
KeLowerIrql(pState->uchOldIrql);
pState->uchOldIrql = 255;
}
RTDECL(bool) RTThreadIsInInterrupt(RTTHREAD hThread)
{
Assert(hThread == NIL_RTTHREAD); NOREF(hThread);
KIRQL CurIrql = KeGetCurrentIrql();
return CurIrql > PASSIVE_LEVEL; /** @todo Is there a more correct way? */
}