// Copyright (c) 2007-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\memmodel\epoc\multiple\x86\xmmu.cia
// 
//

#include <x86_mem.h>

#if defined(KMMU)
extern "C" void __DebugMsgFlushTLB();
extern "C" void __DebugMsgLocalFlushTLB();
extern "C" void __DebugMsgTotalFlushTLB();
extern "C" void __DebugMsgINVLPG(int a);
#endif


extern "C"
{


__NAKED__ void __fastcall DoInvalidateTLBForPage(TLinAddr /*aLinAddr*/)
//
// Flush a specified virtual address from the TLB.
//
	{
	ASM_DEBUG1(INVLPG,ecx)
	asm("invlpg [ecx]");
	asm("ret");
	}

// On 486 and Pentium this invalidates all TLB entries.
// On P6 and later CPUs it only invalidates non-global TLB entries.
__NAKED__ void DoLocalInvalidateTLB()
	{
	ASM_DEBUG0(LocalFlushTLB)
	asm("mov eax, cr3");
	asm("mov cr3, eax");
	asm("ret");
	}

// This function is only used on P6 and later CPUs.
// It invalidates all TLB entries, including global ones.
extern "C" __NAKED__ void DoTotalInvalidateTLB()
	{
	ASM_DEBUG0(TotalFlushTLB)
	asm("pushfd");
	asm("mov eax, cr3");
	MOV_ECX_CR4;
	asm("mov edx, ecx");
	asm("and dl, 0x7f");
	asm("cli");
	MOV_CR4_EDX;
	asm("mov cr3, eax");
	MOV_CR4_ECX;
	asm("popfd");
	asm("ret");
	}

// Invalidate all TLB entries regardless of CPU type.
__NAKED__ void DoInvalidateTLB()
	{
	ASM_DEBUG0(FlushTLB)
	asm("mov edx, [%a0]": : "i"(&X86_UseGlobalPTEs));
	asm("mov eax, cr3");
	asm("cmp edx, 0");
	asm("jz no_global_pages");
	MOV_ECX_CR4;
	asm("mov edx, ecx");
	asm("and dl, 0x7f");
	asm("pushfd");
	asm("cli");
	MOV_CR4_EDX;
	asm("mov cr3, eax");
	MOV_CR4_ECX;
	asm("popfd");
	asm("ret");
	asm("no_global_pages:");
	asm("mov cr3, eax");
	asm("ret");
	}
}

__NAKED__ void DMemModelThread::RestoreAddressSpace()
	{
#ifndef __SMP__
	//SMP FIXME
	asm("mov eax, [%a0]": : "i"(&TheScheduler.iCurrentThread));

	// edx = current thread owning process...
	asm("mov edx, 0");
	asm("lea edx, [edx+%0]": : "i"_FOFF(DThread,iNThread));
	asm("neg edx");
	asm("mov edx, [eax+edx+%0]": : "i"_FOFF(DThread,iOwningProcess));

	// update page directory and address space values...
	asm("cli");
	asm("mov [%a0], edx": :"i"(&TheScheduler.iAddressSpace));
	asm("mov [eax+%0], edx": : "i"_FOFF(NThreadBase,iAddressSpace));
	asm("mov edx, [edx+%0]": : "i"_FOFF(DMemModelProcess,iGlobalPageDir));
	asm("mov cr3, edx");
	asm("sti");
#endif
	asm("ret");
	}


