How to properly use MmMapIoSpace to read physical memory?

I use a UEFI boot-loader to deposit some data in a region of physical memory.
I would like to retrieve said data using a driver.
And with MmMapIoSpace that works great.
That is until I enable this driver verifier contraption of MSFT

With it it bugchecks 0x83 “The driver called MmMapIoSpace without having locked down the MDL pages. The physical pages represented by the physical address range being mapped must have been locked down prior to making this call.”

How do I locked down the pages?

I saw many users here asking questions about MmMapIoSpace and driver verifier but it did not seam anyone of them got an answer, one suggestion was to use MmAllocateContiguousMemorySpecifyCache but that does not work probably because the UEFI allocates the region properly so that windows does not overwrite it.

So what I need is a foll prof way to read physical memory such that driver verifier does not complain.

Any help would be greatly appreciated.

Cheers
David

So, you get a physical memory pointer from UEFI, and you want to map that area, yes? How does UEFI reserve the memory, and where is it located? It sounds suspiciously like the pages are part of Windows main memory… and that would be a problem.

For many years Windows allowed you to deliberately abuse MmMapIoSpace to map “stuff” that wasn’t in I/O Space (which is what you are apparently doing)… which in Windows we would define as being memory ON a device. There was a check for this in the checked build… I’m glad to see Verifier has caught up with the times.

If the memory allocated by UEFI is in the PFN, you could build an MDL, lock the pages with MmProbeAndLockPages and map the pages with MmMapLockedPagesSpecifyCache.

You could also try MmAllocateMdlForIoSpace and then MmMapLockedPagesSpecifyCache. If fact, it’s so easy, that would probably be the first thing I tried.

Peter

@“Peter_Viscarola_(OSR)” said:> If the memory allocated by UEFI is in the PFN, you could build an MDL, lock the pages with MmProbeAndLockPages and map the pages with MmMapLockedPagesSpecifyCache.

There is a caveat here, to build an MDL the legacy way (IoAllocateMdl) requires a kernel VA. That’s what MmMapIoSpace returns, so he cannot build the MDL before that which the bugcheck requires.

It looks like the bugcheck is new and the rules of the interface have changed. None of the samples that make use of MmMapIoSpace that I have seen call MmProbeAndLock pages before calling MmMapIoSpace.

Like you said, apparently what is needed is MmAllocateMdlForIoSpace, which is a new interface.

//Daniel

@Daniel_Terhell The rules haven’t changed. The OP is abusing the API in a way it was never meant to be used. If you’re using the function to map memory on your device… which has been the intended use of the function since forever… then you’re good to go.

If, OTOH, you use this to map an arbitrary PA that’s in main memory… Verifier finally calls you out. Like I said, the was an assert in the checked build all the way back to NT 3.5 at least.

No change… just enforcing the existing contract. I think.

Peter

The OP found a solution that does the exact same thing without upsetting the verifier:


	HANDLE			 h_mem;
	UNICODE_STRING   u_name;
	OBJECT_ATTRIBUTES obj_a;
	PVOID			 p_mem = NULL;
	SIZE_T			 u_size = PAGE_SIZE;

	RtlInitUnicodeString(&u_name, L"\\Device\\PhysicalMemory");
	InitializeObjectAttributes(&obj_a, &u_name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, (HANDLE)NULL, (PSECURITY_DESCRIPTOR)NULL);
	if (NT_SUCCESS(ZwOpenSection(&h_mem, SECTION_ALL_ACCESS, &obj_a)))
	{
		if (NT_SUCCESS(ZwMapViewOfSection(h_mem, NtCurrentProcess(), &p_mem, 0L, u_size, &addr, &u_size, ViewShare, 0, PAGE_READWRITE)))
		{
			__try 
			{
				// here the OP does his thing ;)
			}
			__except (EXCEPTION_EXECUTE_HANDLER) {
				//status = GetExceptionCode();
			}

			ZwUnmapViewOfSection(NtCurrentProcess(), &p_mem);
		}

		ZwClose(h_mem);
	}

About the UEFI part I use gBS->AllocatePages the last argument allows me to specify a desired physical address, so it eider succeeds and allocates memory at the desired location or fails I look for a free page in the range 0x00100000 to 0x01000000 in step of 1 MB I use the first free I find.
The content is marked by a magic value and in the driver I iterate through the same physical memory range and look for the magic value and if I find it success!

Should I try using MmAllocateMdlForIoSpace just for fun or would that be also a less elegant solution?

Cheers
David

What guarantee do you have that the operating system won’t immediately wipe that memory for its own use?