二叉树中创建一个MEMORY_AREA节点:
二叉树中创建一个MEMORY_AREA节点:
MmCreateMemoryArea()
参数AddressSpace是MADDRESS SPACE结构指针,所指向的数据结构代表着一个进程的用 户空间。
参数BaseAddress是个指针,用来给定和返回内存区块的基地址
文章目录
MmCreateMemoryArea()
c
/**
* @name MmCreateMemoryArea
*
* Create a memory area.
*
* @param AddressSpace
* Address space to create the area in.
* @param Type
* Type of the memory area.
* @param BaseAddress
* Base address for the memory area we're about the create. On
* input it contains either 0 (auto-assign address) or preferred
* address. On output it contains the starting address of the
* newly created area.
* @param Length
* Length of the area to allocate.
* @param Attributes
* Protection attributes for the memory area.
* @param Result
* Receives a pointer to the memory area on successful exit.
*
* @return Status
*
* @remarks Lock the address space before calling this function.
*/
NTSTATUS STDCALL
MmCreateMemoryArea(PMADDRESS_SPACE AddressSpace,
ULONG Type,
PVOID *BaseAddress,
ULONG_PTR Length,
ULONG Protect,
PMEMORY_AREA *Result,
BOOLEAN FixedAddress,
ULONG AllocationFlags,
PHYSICAL_ADDRESS BoundaryAddressMultiple)
{
PVOID EndAddress;
ULONG Granularity;
ULONG tmpLength;
PMEMORY_AREA MemoryArea;
DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
"*BaseAddress %p, Length %p, AllocationFlags %x, "
"FixedAddress %x, Result %p)\n",
Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
FixedAddress, Result);
MmVerifyMemoryAreas(AddressSpace);//检测该AVL树是否存在问题
//根据Type选择相应的粒度
Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
//if 用户不要求从固定地址处开始分配
if ((*BaseAddress) == 0 && !FixedAddress)
{
//不受给定地址的约束,只要找到一个够大的空隙即可
tmpLength = PAGE_ROUND_UP(Length);
//根据用户空间找到一块符合的Area,并返回其首地址
*BaseAddress = MmFindGap(AddressSpace,
tmpLength,
Granularity,
(AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN);
if ((*BaseAddress) == 0)
{
DPRINT("No suitable gap\n");
return STATUS_NO_MEMORY;
}
}
else//用户给定了基址,就必须从那儿开始分配
{
tmpLength = Length + ((ULONG_PTR) *BaseAddress
- (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
*BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
if (AddressSpace->LowestAddress == MmSystemRangeStart &&
*BaseAddress < MmSystemRangeStart)
{
//给定的空间为系统空间,但是地址落在用户空间,严重错误CHECKPOINT;
CHECKPOINT;
return STATUS_ACCESS_VIOLATION;
}
if (AddressSpace->LowestAddress < MmSystemRangeStart &&
(ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
{
//所要求的区间跨越用户空间和系统空间的分界,严重错误CHECKPOINT;
CHECKPOINT;
return STATUS_ACCESS_VIOLATION;
}
//测试要分配的区域完全落在指定地址空间内部
if (BoundaryAddressMultiple.QuadPart != 0)
{
EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
}
//确认所要求的区间尚术分配
if (MmLocateMemoryAreaByRegion(AddressSpace,
*BaseAddress,
tmpLength) != NULL)
{
//所要求的区间已经分配,失敗
DPRINT("Memory area already occupied\n");
return STATUS_CONFLICTING_ADDRESSES;
}
}
//创建MEMORY AREA节点,把这块区域分配出去
MemoryArea = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
TAG_MAREA);
RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
MemoryArea->Type = Type;
MemoryArea->StartingAddress = *BaseAddress;
MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength);
MemoryArea->Protect = Protect;
MemoryArea->Flags = AllocationFlags;
//MemoryArea->LockCount = 0;
MemoryArea->PageOpCount = 0;
MemoryArea->DeleteInProgress = FALSE;
//将所创建节点插入一又树
MmInsertMemoryArea(AddressSpace, MemoryArea);
*Result = MemoryArea;
DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
return STATUS_SUCCESS;
}
//二叉树中创建-个MEMORY AREA节点
/*
参数AddressSpace是MADDRESS SPACE结构指针,所指向的数据结构代表着一个进程的用 户空间。
参数BaseAddress是个指针,用来给定和返回内存区块的基地址 :
参数Length、Protect的意义 则不言自明。
参数FixedAddress为TRUE说明给定的地址不容改变,为FALSE则表示若不能满足 要求也可以浮动, 。
参数AllocationFlags : 分配标志TopDown ? TopUp
参数BoundaryAddressMultiple此分配不得跨越的物理地址倍数
*/