在Windows上模拟(惰性)NAND内存



我正在一个模拟NAND(256MB或1GB(的DLL中运行固件模拟。我希望避免在堆上为此分配内存,而是使用虚拟内存进行分配。

存储器最初需要被清除到0xFF(就像NAND一样(。然而,我不想为初始化付费(也不想提交未访问的页面(。因此,理想情况下,它应该只在访问时进行分配。并且我不需要保留模拟退出后的数据。

最初的想法是

  1. VirtualAlloc。不确定,但认为也许可以使用保护页,然后在第一次访问时捕获异常。不确定DLL处理这种SEH异常是否理想?或者有更好的方法吗?

  2. 创建一个初始化为0xFF的大文件。然后映射文件的视图和写入时的副本。有人知道是否可以创建一个带有回调的文件来提供初始数据吗?

想想可能的路,但想知道这是否真的是最好的选择。

编辑: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, 0, &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, 0, MEM_RELEASE);
}
RemoveVectoredExceptionHandler(pv);
}
}

最新更新