在Windows上模拟惰性NAND内存

问题描述

我正在具有NAND(256MB或1GB)的DLL中运行固件仿真。我想避免在堆上为此分配内存,而是使用虚拟内存分配。

最初需要将内存清除为0xFF(与NAND类似)。但是,我不想为该初始化付费(也不提交未访问的页面)。因此,理想情况下,仅应在访问时进行分配。而且我不需要在模拟退出后保留数据。

最初的想法是

  1. VirtualAlloc。不确定,但可能会使用保护页,然后在首次访问时捕获异常。不确定DLL处理此类SEH异常是否理想?还是有更好的方法

  2. 创建一个初始化为0xFF的大文件。然后使用写时复制映射文件视图。 有人知道是否可以通过提供初始数据的回调创建文件吗?

想一想1)前进的道路,但想知道这是否真的是最好的选择。

编辑: 3)我想出了另一个方法,可以避免异常处理程序,也可以避免创建大文件: 创建一个与dwAllocationGranularity大小相同的文件(通常为64KiB)。填充0xFF。然后,使用MapViewOfFileEx + FILE_MAP_copY在连续的内存中创建该副本的多个写时复制视图(在初始VirtualAlloc / VirtualFree之后获得合适的基地址,我们希望可以分配并置的视图)。需要对此进行更全面的测试-对潜在的线程竞赛稍有担心。.我实际上只使用一个线程,但是CRT确实也可以启动几个线程。 这意味着任何只读取虚拟NAND的代码也不会导致所有页面都被提交。

解决方法

是的,基本上1是最佳解决方案。只有我做下一个更改-使用VEH代替 SEH - SEH 处理程序仅在您访问其中的内存时才会调用,以防万一 VEH -访问可以是任何上下文和线程。而不是使用保护页,我最初是仅保留内存的区域,而没有实际分配。因此,任何对内存区域的访问都会导致异常,您可以在 VEH 中进行处理-提交内存并填充0xFF模式。演示代码

PVOID g_NandBegin;
SIZE_T g_NandSize = 0x1000000;

LONG NTAPI Vex(::PEXCEPTION_POINTERS ExceptionInfo)
{
    ::PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;

    if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION &&
        ExceptionRecord->NumberParameters > 1)
    {
        PVOID pv = (PVOID)ExceptionRecord->ExceptionInformation[1];

        if ((ULONG_PTR)pv - (ULONG_PTR)g_NandBegin < g_NandSize)
        {
            SIZE_T RegionSize = 1;
            if (0 <= NtAllocateVirtualMemory(NtCurrentProcess(),&pv,&RegionSize,MEM_COMMIT,PAGE_READWRITE))
            {
                RtlFillMemoryUlong(pv,RegionSize,MAXULONG);
                return EXCEPTION_CONTINUE_EXECUTION;
            }
        }
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

void dc()
{
    if (PVOID pv = AddVectoredExceptionHandler(TRUE,Vex))
    {
        if (g_NandBegin = VirtualAlloc(0,g_NandSize,MEM_RESERVE,PAGE_READWRITE))
        {
            ULONG seed = ~GetTickCount();
            int n = 0x100;

            do 
            {
                if (*(UCHAR*)((PBYTE)g_NandBegin + (((ULONG64)RtlRandomEx(&seed) * g_NandSize) >> 32)) != 0xFF)
                {
                    __debugbreak();
                }
            } while (--n);

            VirtualFree(g_NandBegin,MEM_RELEASE);
        }
        RemoveVectoredExceptionHandler(pv);
    }
}