Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ntoskrnl/include/config.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#pragma once

// Enable global page support.
// #define _GLOBAL_PAGES_ARE_AWESOME_
#define _GLOBAL_PAGES_ARE_AWESOME_
19 changes: 0 additions & 19 deletions ntoskrnl/include/internal/amd64/ke.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,25 +256,6 @@ KeRestoreInterrupts(BOOLEAN WereEnabled)
if (WereEnabled) _enable();
}

//
// Invalidates the TLB entry for a specified address
//
FORCEINLINE
VOID
KeInvalidateTlbEntry(IN PVOID Address)
{
/* Invalidate the TLB entry for this address */
__invlpg(Address);
}

FORCEINLINE
VOID
KeFlushProcessTb(VOID)
{
/* Flush the TLB by resetting CR3 */
__writecr3(__readcr3());
}

FORCEINLINE
VOID
KeSweepICache(IN PVOID BaseAddress,
Expand Down
2 changes: 2 additions & 0 deletions ntoskrnl/include/internal/arch/ke.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#ifdef _M_IX86
#include <internal/i386/ke.h>
#include <internal/x86x64/ke.h>
#elif defined(_M_PPC)
#include <internal/powerpc/ke.h>
#elif defined(_M_MIPS)
Expand All @@ -29,6 +30,7 @@
#include <internal/arm/ke.h>
#elif defined(_M_AMD64)
#include <internal/amd64/ke.h>
#include <internal/x86x64/ke.h>
#else
#error "Unknown processor"
#endif
Expand Down
30 changes: 28 additions & 2 deletions ntoskrnl/include/internal/arm/ke.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,20 +98,46 @@ KeRestoreInterrupts(BOOLEAN WereEnabled)
if (WereEnabled) _enable();
}

static const ULONG KxFlushIndividualProcessPagesMaximum = 1024; // Based on Linux tlb_single_page_flush_ceiling
static const ULONG KxFlushIndividualGlobalPagesMaximum = 1024; // Just a guess

//
// Invalidates the TLB entry for a specified address
//
FORCEINLINE
VOID
KeInvalidateTlbEntry(IN PVOID Address)
KxFlushSingleCurrentTb(
_In_ PVOID Address)
{
/* Invalidate the TLB entry for this address */
KeArmInvalidateTlbEntry(Address);
}

FORCEINLINE
VOID
KeFlushProcessTb(VOID)
KxFlushRangeCurrentTb(
_In_ PVOID Address,
_In_ ULONG NumberOfPages)
{
/* Invalidate the TLB entry for each page */
for (ULONG i = 0; i < NumberOfPages; i++)
{
KeArmInvalidateTlbEntry((PVOID)((ULONG_PTR)Address + (i * PAGE_SIZE)));
}
}

FORCEINLINE
VOID
KxFlushProcessCurrentTb(
VOID)
{
KeArmFlushTlb();
}

FORCEINLINE
VOID
KxFlushEntireCurrentTb(
VOID)
{
KeArmFlushTlb();
}
Expand Down
19 changes: 0 additions & 19 deletions ntoskrnl/include/internal/i386/ke.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,25 +350,6 @@ KeQueryInterruptHandler(IN ULONG Vector)
(Pcr->IDT[Entry].Offset & 0xFFFF));
}

//
// Invalidates the TLB entry for a specified address
//
FORCEINLINE
VOID
KeInvalidateTlbEntry(IN PVOID Address)
{
/* Invalidate the TLB entry for this address */
__invlpg(Address);
}

FORCEINLINE
VOID
KeFlushProcessTb(VOID)
{
/* Flush the TLB by resetting CR3 */
__writecr3(__readcr3());
}

FORCEINLINE
VOID
KeSweepICache(IN PVOID BaseAddress,
Expand Down
30 changes: 29 additions & 1 deletion ntoskrnl/include/internal/ke.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,15 @@ KiIpiSignalPacketDoneAndStall(
IN volatile PULONG ReverseStall
);

VOID
NTAPI
KiIpiSendRequest(
_In_ KAFFINITY TargetSet,
_In_ PKIPI_WORKER WorkerRoutine,
_In_ PVOID Parameter1,
_In_ PVOID Parameter2,
_In_ PVOID Parameter3);

/* next file ***************************************************************/

UCHAR
Expand Down Expand Up @@ -819,7 +828,26 @@ KiHandleNmi(VOID);

VOID
NTAPI
KeFlushCurrentTb(VOID);
KeFlushSingleTb(
_In_ PVOID Address,
_In_ BOOLEAN AllProcessors);

VOID
NTAPI
KeFlushRangeTb(
_In_ PVOID Address,
_In_ ULONG NumberOfPages,
_In_ BOOLEAN Global);

VOID
NTAPI
KeFlushProcessTb(VOID);

VOID
NTAPI
KeFlushEntireTb(
_In_ BOOLEAN Invalid,
_In_ BOOLEAN AllProcessors);

BOOLEAN
NTAPI
Expand Down
8 changes: 8 additions & 0 deletions ntoskrnl/include/internal/ke_x.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ extern "C"
{
#endif

FORCEINLINE
PKPROCESS
KeGetCurrentProcess(VOID)
{
/* Get the current process */
return KeGetCurrentThread()->ApcState.Process;
}

#ifndef _M_ARM
FORCEINLINE
KPROCESSOR_MODE
Expand Down
90 changes: 90 additions & 0 deletions ntoskrnl/include/internal/x86x64/ke.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: MIT (https://spdx.org/licenses/MIT)
* PURPOSE: Architecture specific support routines shared between x86 and x64
* COPYRIGHT: Copyright 2025 Timo Kreuzer <[email protected]>
*/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

extern ULONG64 KeFeatureBits;

static const ULONG KxFlushIndividualProcessPagesMaximum = 33; // Based on Linux tlb_single_page_flush_ceiling
static const ULONG KxFlushIndividualGlobalPagesMaximum = 100; // Just a guess
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these variables for? Some sort of arbitrary threshold that when reached in KeFlushRangeTb and friends, a full flush is done?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Use the source, Luke.


/*!
* \brief Flushes the current processor's TLB for a single page.
* \note This function flushes global pages.
*/
FORCEINLINE
VOID
KxFlushSingleCurrentTb(
_In_ PVOID Address)
{
/* Invalidate the TLB entry for this address */
__invlpg(Address);
}

/*!
* \brief Flushes the current processor's TLB for a range of pages.
* \param Address The starting address of the range to flush.
* \param NumberOfPages The number of pages to flush.
* \note This function flushes global pages. It does not optimize for large ranges.
*/
FORCEINLINE
VOID
KxFlushRangeCurrentTb(
_In_ PVOID Address,
_In_ ULONG NumberOfPages)
{
/* Invalidate the TLB entry for each page */
for (ULONG i = 0; i < NumberOfPages; i++)
{
__invlpg((PVOID)((ULONG_PTR)Address + (i * PAGE_SIZE)));
}
}

/*!
* \brief Flushes the current processor's TLB, excluding global pages.
*/
FORCEINLINE
VOID
KxFlushProcessCurrentTb(
VOID)
{
/* Flush the TLB excluding global pages */
__writecr3(__readcr3());
}

/*!
* \brief Flushes the current processor's entire TLB, including global pages.
*/
FORCEINLINE
VOID
KxFlushEntireCurrentTb(
VOID)
{
#ifdef _GLOBAL_PAGES_ARE_AWESOME_
/* Check if global pages are enabled in CR4 */
if (KeFeatureBits & KF_GLOBAL_PAGE)
{
/* Disable and restore PGE. This will flush the entire TLB */
ULONG64 oldCr4 = __readcr4();
__writecr4(oldCr4 & ~CR4_PGE);
__writecr4(oldCr4);
}
else
#endif
{
/* We don't use global pages, reset CR3 instead */
__writecr3(__readcr3());
}
}

#ifdef __cplusplus
} // extern "C"
#endif
28 changes: 0 additions & 28 deletions ntoskrnl/ke/amd64/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,14 +523,6 @@ KiGetCacheInformation(VOID)
}
}

VOID
NTAPI
KeFlushCurrentTb(VOID)
{
/* Flush the TLB by resetting CR3 */
__writecr3(__readcr3());
}

VOID
NTAPI
KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
Expand Down Expand Up @@ -649,26 +641,6 @@ KiRestoreProcessorState(
KiRestoreProcessorControlState(&Prcb->ProcessorState);
}

VOID
NTAPI
KeFlushEntireTb(IN BOOLEAN Invalid,
IN BOOLEAN AllProcessors)
{
KIRQL OldIrql;

// FIXME: halfplemented
/* Raise the IRQL for the TB Flush */
OldIrql = KeRaiseIrqlToSynchLevel();

/* Flush the TB for the Current CPU, and update the flush stamp */
KeFlushCurrentTb();

/* Update the flush stamp and return to original IRQL */
InterlockedExchangeAdd(&KiTbFlushTimeStamp, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, by the way, about this timestamp, you may find this reading interesting: https://azius.com/the-page-fault-in-nonpaged-pool-syndrome/
(The MS KB mentioned in the article can be found here.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I am aware of it. We don't make use of this feature and I doubt we ever will, because IMO it's pointless. It doesn't work in user-mode, and in kernel mode there are much better ways to avoid flushes.

KeLowerIrql(OldIrql);

}

NTSTATUS
NTAPI
KxSaveFloatingPointState(OUT PKFLOATING_SAVE FloatingState)
Expand Down
3 changes: 3 additions & 0 deletions ntoskrnl/ke/amd64/freeze.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ KiProcessorFreezeHandler(
/* Restore the processor state */
KiRestoreProcessorState(TrapFrame, ExceptionFrame);

/* Flush the TLB on this processor */
KxFlushEntireCurrentTb();

/* We are running again now */
CurrentPrcb->IpiFrozen = IPI_FROZEN_STATE_RUNNING;

Expand Down
28 changes: 28 additions & 0 deletions ntoskrnl/ke/amd64/ipi.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,34 @@

/* FUNCTIONS *****************************************************************/

VOID
NTAPI
KiIpiSendRequest(
_In_ KAFFINITY TargetSet,
_In_ PKIPI_WORKER WorkerRoutine,
_In_ PVOID Parameter1,
_In_ PVOID Parameter2,
_In_ PVOID Parameter3)
{
KIRQL OldIrql;

if (KeNumberProcessors > 1)
{
ASSERT(FALSE);
}

KeRaiseIrql(IPI_LEVEL, &OldIrql);

if (TargetSet & KeGetCurrentPrcb()->SetMember)
{
WorkerRoutine(NULL, Parameter1, Parameter2, Parameter3);
}
else
__debugbreak();

KeLowerIrql(OldIrql);
}

VOID
FASTCALL
KiIpiSend(
Expand Down
3 changes: 3 additions & 0 deletions ntoskrnl/ke/amd64/kiinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ KiSystemStartup(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
/* Set processor as active */
KeActiveProcessors |= 1ULL << Cpu;

/* We are running the initial system process now */
InterlockedOr64(&KiInitialProcess.Pcb.ActiveProcessors, 1ULL << Cpu);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like this is already done in KiInitializeHandBuiltThread (see line 134) already, no? (it's invoked either for CPU 0 byKiInitializeKernel() -- which in turn is invoked from KiSystemStartupBootStack, or, it's invoked for CPU != 0 directly by KiSystemStartupBootStack()).


/* Release lock */
InterlockedAnd64((PLONG64)&KiFreezeExecutionLock, 0);

Expand Down
2 changes: 2 additions & 0 deletions ntoskrnl/ke/amd64/stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ KiSwapProcess(IN PKPROCESS NewProcess,
#ifdef CONFIG_SMP
/* Update active processor mask */
InterlockedXor64((PLONG64)&NewProcess->ActiveProcessors, Pcr->Prcb.SetMember);
NT_ASSERT((NewProcess->ActiveProcessors & Pcr->Prcb.SetMember) != 0);
InterlockedXor64((PLONG64)&OldProcess->ActiveProcessors, Pcr->Prcb.SetMember);
NT_ASSERT((OldProcess->ActiveProcessors & Pcr->Prcb.SetMember) == 0);
#endif

/* Update CR3 */
Expand Down
6 changes: 1 addition & 5 deletions ntoskrnl/ke/amd64/thrdini.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,7 @@ KiSwapContextResume(
NewProcess = NewThread->ApcState.Process;
if (OldProcess != NewProcess)
{
/* Switch address space and flush TLB */
__writecr3(NewProcess->DirectoryTableBase[0]);

/* Set new TSS fields */
//Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
KiSwapProcess(NewProcess, OldProcess);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: a similar change could be done in x86 in KiSwapContextExit (compare with the x86 KiSwapProcess implementation) -- this would ensure having the SMP-specific code run there as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an SMP PR and won't change anything in x86 that isn't strictly needed. I'll leave that part to @DarkFire01.

}

/* Set TEB pointer and GS base */
Expand Down
Loading