GFP_KERNEL:用于内核空间的内存分配,可能休眠; GFP_ATOMIC:用于原子性的内存分配,不会休眠;典型原子性场景有中断处理程序,软中断,tasklet等 kmalloc内存分配最终总是调用__get_free_pages 来进行实际的分配,故前缀都是GFP_开头。 kmalloc分最多只能分配32个page大小的内存,每个page=4k,也就是128K大小,其中16个字节...
get_zeroed_page(gfp_mask) 分配一页,并填充内容为0,返回指向其逻辑地址的指针 get_zeroed_page:对于用户空间,这个方法能保障系统敏感数据不会泄露 page_address: 把给定的页转换成逻辑地址 页释放函数描述 __free_pages(page, order) 从page开始,释放2^order个页 free_pages(addr, order) 从地址addr开始,释放...
clean_pte_table(page_address(pte));//如果分配的页表项不在高内存中,调用 clean_pte_table(page_address(pte)) 清理页表项相关的缓存。 return pte;//返回分配的页表项指针。 } 定义PMD 填充函数 __pmd_populate函数:内部辅助函数,用于填充PMD条目。 pmd_populate_kernel函数:用于内核空间的PMD填充。 pmd_po...
虚拟地址的4个页表段page_index可以看做在页表中的索引。 上图中的页操作函数可供我们遍历页表,如通过 "current" 指针就可以得到进程描述符,然后得到内存描述符下的 "pgd" 指针,从而可以得到该虚拟地址对应的物理地址(即上图中最后一层就是 page number + offset 得到物理地址),通过物理地址的前52位可以得到该...
申请page frame 1)alloc_pages i.返回struct page ii. 默认分配的物理内存来自ZONE_NORMAL 或ZONE_DMA iii.若gdf_mask 指定__GFP_HIGHMEM, 则优先ZONE_HIGH xi. 需调用地址转换函数 ZONE_DMA or ZONE_NORMAL: 可直接使用page_address ZONE_HIGHMEM: ...
staticinlineunsignedlongvirt_to_phys(volatilevoid*address) { return__pa((void*)address); } #define __va(x) ((x) + PAGE_OFFSET) staticinlinevoid*phys_to_virt(unsignedlongaddress) { return__va(address); } 1. 2. 3. 4. 5.
GFP_KERNEL参数是gfp_mask标志的一个例子 调用_get_free_pages(*)之后要注意进行错误检查。内核分配可能失败,因此你的代码必须进行检查并做相应的处理。这意味在此之前,你所做的所有工作可能前功尽弃,甚至还需要回归到原来的状态。正因为如此,在程序开始时就先进行内存分配时很有意义的,这能让错误处理得到容易一点...
34if(is_kernel_text(address) || is_kernel_text(address2)) 35set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); 36else 37set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); 38pfn += PTRS_PER_PTE; 39}else{ 40pte = one_page_table_init(pmd); ...
该函数返回address在页中间目录中对应表项的线性地址。 2.1.4 PAGE_SHIFT及相关宏 表示线性地址offset字段的位数。该宏的值被定义为12位,即页的大小为4KB。与它对应的宏有PAGE_SIZE,它返回一个页的大小;PAGE_MASK用来屏蔽offset字段,其值为oxfffff000。PTRS_PER_PTE表明页表在线性地址中占据9位。
为了节省 " 内存管理 " 的内存开销 , 物理页的描述符 page 中都是 union 联合体 , 如 : 代码语言:javascript 复制 struct page{union{struct address_space*mapping;/* If low bit clear, points to * inode address_space, or NULL. * If page mapped as anonymous ...