更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_vm_fault.c 文件参考

浏览源代码.

函数

STATIC STATUS_T OsVmRegionPermissionCheck (LosVmMapRegion *region, UINT32 flags)
 
STATIC VOID OsFaultTryFixup (ExcContext *frame, VADDR_T excVaddr, STATUS_T *status)
 
STATIC STATUS_T OsDoReadFault (LosVmMapRegion *region, LosVmPgFault *vmPgFault)
 
STATIC LosVmPageOsCowUnmapOrg (LosArchMmu *archMmu, LosVmMapRegion *region, LosVmPgFault *vmf)
 
status_t OsDoCowFault (LosVmMapRegion *region, LosVmPgFault *vmPgFault)
 
status_t OsDoSharedFault (LosVmMapRegion *region, LosVmPgFault *vmPgFault)
 在共享线性区写文件操作发生缺页的情况处理,因为线性区是共享的 更多...
 
STATIC STATUS_T OsDoFileFault (LosVmMapRegion *region, LosVmPgFault *vmPgFault, UINT32 flags)
 
STATUS_T OsVmPageFaultHandler (VADDR_T vaddr, UINT32 flags, ExcContext *frame)
 

变量

char __exc_table_start []
 
char __exc_table_end []
 

函数说明

◆ OsCowUnmapOrg()

STATIC LosVmPage * OsCowUnmapOrg ( LosArchMmu archMmu,
LosVmMapRegion region,
LosVmPgFault vmf 
)

在文件 los_vm_fault.c144 行定义.

145{
146 UINT32 intSave;
147 LosVmPage *oldPage = NULL;
148 LosMapInfo *mapInfo = NULL;
149 LosFilePage *fpage = NULL;
150 VADDR_T vaddr = (VADDR_T)vmf->vaddr;
151
152 LOS_SpinLockSave(&region->unTypeData.rf.vnode->mapping.list_lock, &intSave);
153 fpage = OsFindGetEntry(&region->unTypeData.rf.vnode->mapping, vmf->pgoff);
154 if (fpage != NULL) {
155 oldPage = fpage->vmPage;
156 OsSetPageLocked(oldPage);
157 mapInfo = OsGetMapInfo(fpage, archMmu, vaddr);
158 if (mapInfo != NULL) {
159 OsUnmapPageLocked(fpage, mapInfo);
160 } else {
161 LOS_ArchMmuUnmap(archMmu, vaddr, 1);
162 }
163 } else {
164 LOS_ArchMmuUnmap(archMmu, vaddr, 1);
165 }
166 LOS_SpinUnlockRestore(&region->unTypeData.rf.vnode->mapping.list_lock, intSave);
167
168 return oldPage;
169}
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
VOID LOS_SpinUnlockRestore(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_spinlock.c:108
VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
Definition: los_spinlock.c:98
unsigned long VADDR_T
Definition: los_typedef.h:208
unsigned int UINT32
Definition: los_typedef.h:57
LosMapInfo * OsGetMapInfo(LosFilePage *page, LosArchMmu *archMmu, VADDR_T vaddr)
通过虚拟地址获取文件页映射信息,archMmu每个进程都有属于自己的mmu
VOID OsUnmapPageLocked(LosFilePage *page, LosMapInfo *info)
Definition: los_vm_scan.c:44
STATIC INLINE VOID OsSetPageLocked(LosVmPage *page)
给页面贴上被锁的标签
LosFilePage * OsFindGetEntry(struct page_mapping *mapping, VM_OFFSET_T pgoff)
文件页结构体
struct VmPage * vmPage
物理页框
虚拟地址和文件页的映射信息,在一个进程使用文件页之前,需要提前做好文件页在此内存空间的映射关系,如此通过虚拟内存就可以对文件页读写操作.
unsigned long pgoff
Definition: los_vm_map.h:97
VADDR_T vaddr
Definition: los_vm_map.h:98
struct VmMapRegion::@4::VmRegionFile rf
union VmMapRegion::@4 unTypeData
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
函数调用图:
这是这个函数的调用关系图:

◆ OsDoCowFault()

status_t OsDoCowFault ( LosVmMapRegion region,
LosVmPgFault vmPgFault 
)

here we get two conditions, 1.this page hasn't mapped or mapped from pagecache, we can take it as a normal file cow map. 2.this page has done file cow map, we can take it as a anonymous cow map.

在文件 los_vm_fault.c172 行定义.

173{
174 STATUS_T ret;
175 VOID *kvaddr = NULL;
176 PADDR_T oldPaddr = 0;
177 PADDR_T newPaddr;
178 LosVmPage *oldPage = NULL;
179 LosVmPage *newPage = NULL;
180 LosVmSpace *space = NULL;
181
182 if ((vmPgFault == NULL) || (region == NULL) ||
183 (region->unTypeData.rf.vmFOps == NULL) || (region->unTypeData.rf.vmFOps->fault == NULL)) {
184 VM_ERR("region args invalid");
185 return LOS_ERRNO_VM_INVALID_ARGS;
186 }
187
188 space = region->space;
189 ret = LOS_ArchMmuQuery(&space->archMmu, (VADDR_T)vmPgFault->vaddr, &oldPaddr, NULL);//查询出老物理地址
190 if (ret == LOS_OK) {
191 oldPage = OsCowUnmapOrg(&space->archMmu, region, vmPgFault);//取消页面映射
192 }
193
194 newPage = LOS_PhysPageAlloc();//分配一个新页面
195 if (newPage == NULL) {
196 VM_ERR("LOS_PhysPageAlloc failed");
197 ret = LOS_ERRNO_VM_NO_MEMORY;
198 goto ERR_OUT;
199 }
200
201 newPaddr = VM_PAGE_TO_PHYS(newPage);//拿到新的物理地址
202 kvaddr = OsVmPageToVaddr(newPage);//拿到新的虚拟地址
203
204 (VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
205 ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针 g_commVmOps.OsVmmFileFault
206 if (ret != LOS_OK) {
207 VM_ERR("call region->vm_ops->fault fail");
208 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
209 goto ERR_OUT;
210 }
211
212 /**
213 * here we get two conditions, 1.this page hasn't mapped or mapped from pagecache,
214 * we can take it as a normal file cow map. 2.this page has done file cow map,
215 * we can take it as a anonymous cow map.
216 */
217 if ((oldPaddr == 0) || (LOS_PaddrToKVaddr(oldPaddr) == vmPgFault->pageKVaddr)) {//没有映射或者 已在pagecache有映射
218 (VOID)memcpy_s(kvaddr, PAGE_SIZE, vmPgFault->pageKVaddr, PAGE_SIZE);//直接copy到新页
219 LOS_AtomicInc(&newPage->refCounts);//引用ref++
221 } else {
222 OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//调用之前 oldPaddr肯定不等于newPaddr
223 /* use old page free the new one */
224 if (newPaddr == oldPaddr) {//注意这里newPaddr可能已经被改变了,参数传入的是 &newPaddr
225 LOS_PhysPageFree(newPage);//释放新页,别浪费的内存,内核使用内存是一分钱当十块用.
226 newPage = NULL;
227 }
228 }
229
230 ret = LOS_ArchMmuMap(&space->archMmu, (VADDR_T)vmPgFault->vaddr, newPaddr, 1, region->regionFlags);//把新物理地址映射给缺页的虚拟地址,这样就不会缺页啦
231 if (ret < 0) {
232 VM_ERR("LOS_ArchMmuMap failed");
233 ret = LOS_ERRNO_VM_NO_MEMORY;
234 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
235 goto ERR_OUT;
236 }
237 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
238
239 if (oldPage != NULL) {
240 OsCleanPageLocked(oldPage);
241 }
242
243 return LOS_OK;
244
245ERR_OUT:
246 if (newPage != NULL) {
247 LOS_PhysPageFree(newPage);
248 }
249 if (oldPage != NULL) {
250 OsCleanPageLocked(oldPage);
251 }
252
253 return ret;
254}
STATIC INLINE VOID LOS_AtomicInc(Atomic *v)
Atomic addSelf.
Definition: los_atomic.h:253
STATUS_T LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间 所谓的map就是生成L1,L2页表项的过程
Definition: los_arch_mmu.c:891
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
Definition: los_arch_mmu.c:569
unsigned long PADDR_T
Definition: los_typedef.h:207
int STATUS_T
Definition: los_typedef.h:215
STATIC LosVmPage * OsCowUnmapOrg(LosArchMmu *archMmu, LosVmMapRegion *region, LosVmPgFault *vmf)
Definition: los_vm_fault.c:144
STATIC INLINE VOID OsCleanPageLocked(LosVmPage *page)
给页面撕掉被锁的标签
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
Definition: los_vm_page.c:120
VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage)
拷贝共享页面
Definition: los_vm_phys.c:602
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
Definition: los_vm_phys.c:546
LosVmPage * LOS_PhysPageAlloc(VOID)
申请一个物理页
Definition: los_vm_phys.c:566
VOID * OsVmPageToVaddr(LosVmPage *page)
通过page获取内核空间的虚拟地址 参考OsArchMmuInit #define SYS_MEM_BASE DDR_MEM_ADDR /* physical memory base 物理地址的起始...
Definition: los_vm_phys.c:288
VADDR_T * LOS_PaddrToKVaddr(PADDR_T paddr)
通过物理地址获取内核虚拟地址
Definition: los_vm_phys.c:688
VADDR_T * pageKVaddr
Definition: los_vm_map.h:99
UINT32 regionFlags
Definition: los_vm_map.h:125
LosVmSpace * space
所属虚拟空间,虚拟空间由多个线性区组成
Definition: los_vm_map.h:121
Atomic refCounts
Definition: los_vm_page.h:57
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosArchMmu archMmu
Definition: los_vm_map.h:157
函数调用图:
这是这个函数的调用关系图:

◆ OsDoFileFault()

STATIC STATUS_T OsDoFileFault ( LosVmMapRegion region,
LosVmPgFault vmPgFault,
UINT32  flags 
)

Page read operation is a simple case, just share the pagecache(save memory) and make a read permission mmapping (region->arch_mmu_flags & (~ARCH_MMU_FLAG_PERM_WRITE)). However for write operation, vmflag (VM_PRIVATE|VM_SHREAD) decides COW or SHARED fault. For COW fault, pagecache is copied to private anonyous pages and the changes on this page won't write through to the underlying file. For SHARED fault, pagecache is mapping with region->arch_mmu_flags and the changes on this page will write through to the underlying file

在文件 los_vm_fault.c323 行定义.

324{
325 STATUS_T ret;
326
327 if (flags & VM_MAP_PF_FLAG_WRITE) {//写页的时候产生缺页
328 if (region->regionFlags & VM_MAP_REGION_FLAG_SHARED) {//共享线性区
329 ret = OsDoSharedFault(region, vmPgFault);//写操作时的共享缺页,最复杂,此页上的更改将写入磁盘文件
330 } else {//非共享线性区
331 ret = OsDoCowFault(region, vmPgFault);//(写时拷贝技术)写操作时的私有缺页,pagecache被复制到私有的任意一个页面上,并在此页面上进行更改,不会直接写入磁盘文件
332 }
333 } else {//读页的时候产生缺页
334 ret = OsDoReadFault(region, vmPgFault);//页面读取操作很简单,只需共享页面缓存(节省内存)并进行读权限映射(region->arch_mmu_flags&(~arch_mmu_FLAG_PERM_WRITE))
335 }
336 return ret;
337}
status_t OsDoSharedFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
在共享线性区写文件操作发生缺页的情况处理,因为线性区是共享的
Definition: los_vm_fault.c:256
status_t OsDoCowFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
Definition: los_vm_fault.c:172
STATIC STATUS_T OsDoReadFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault)
Definition: los_vm_fault.c:100
函数调用图:
这是这个函数的调用关系图:

◆ OsDoReadFault()

STATIC STATUS_T OsDoReadFault ( LosVmMapRegion region,
LosVmPgFault vmPgFault 
)

在文件 los_vm_fault.c100 行定义.

101{
102 status_t ret;
103 PADDR_T paddr;
104 LosVmPage *page = NULL;
105 VADDR_T vaddr = (VADDR_T)vmPgFault->vaddr;
106 LosVmSpace *space = region->space;
107
108 ret = LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, NULL);//查询是否缺页
109 if (ret == LOS_OK) {//注意这里时LOS_OK却返回,都OK了说明查到了物理地址,有页了。
110 return LOS_OK;//查到了就说明不缺页的,缺页就是因为虚拟地址没有映射到物理地址嘛
111 }
112 if (region->unTypeData.rf.vmFOps == NULL || region->unTypeData.rf.vmFOps->fault == NULL) {//线性区必须有实现了缺页接口
113 VM_ERR("region args invalid, file path: %s", region->unTypeData.rf.vnode->filePath);
114 return LOS_ERRNO_VM_INVALID_ARGS;
115 }
116
117 (VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
118 ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);// 函数指针,执行的是g_commVmOps.OsVmmFileFault
119 if (ret == LOS_OK) {
120 paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);//查询物理地址
121 page = LOS_VmPageGet(paddr);//获取page
122 if (page != NULL) { /* just incase of page null */
123 LOS_AtomicInc(&page->refCounts);//ref 自增
124 OsCleanPageLocked(page);
125 }
126 ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1,
127 region->regionFlags & (~VM_MAP_REGION_FLAG_PERM_WRITE));//重新映射为非可写
128 if (ret < 0) {
129 VM_ERR("LOS_ArchMmuMap failed");
130 OsDelMapInfo(region, vmPgFault, false);
131 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
132 return LOS_ERRNO_VM_NO_MEMORY;
133 }
134
135 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
136 return LOS_OK;
137 }
138 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
139
140 return LOS_ERRNO_VM_NO_MEMORY;
141}
int status_t
Definition: los_typedef.h:205
VOID OsDelMapInfo(LosVmMapRegion *region, LosVmPgFault *pgFault, BOOL cleanDirty)
删除映射信息
函数调用图:
这是这个函数的调用关系图:

◆ OsDoSharedFault()

status_t OsDoSharedFault ( LosVmMapRegion region,
LosVmPgFault vmPgFault 
)

在共享线性区写文件操作发生缺页的情况处理,因为线性区是共享的

在文件 los_vm_fault.c256 行定义.

257{
258 STATUS_T ret;
259 UINT32 intSave;
260 PADDR_T paddr = 0;
261 VADDR_T vaddr = (VADDR_T)vmPgFault->vaddr;
262 LosVmSpace *space = region->space;
263 LosVmPage *page = NULL;
264 LosFilePage *fpage = NULL;
265
266 if ((region->unTypeData.rf.vmFOps == NULL) || (region->unTypeData.rf.vmFOps->fault == NULL)) {
267 VM_ERR("region args invalid");
268 return LOS_ERRNO_VM_INVALID_ARGS;
269 }
270
271 ret = LOS_ArchMmuQuery(&space->archMmu, vmPgFault->vaddr, &paddr, NULL);//查询物理地址
272 if (ret == LOS_OK) {
273 LOS_ArchMmuUnmap(&space->archMmu, vmPgFault->vaddr, 1);//先取消映射
274 ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);//再重新映射,为啥这么干,是因为regionFlags变了,
275 if (ret < 0) {
276 VM_ERR("LOS_ArchMmuMap failed. ret=%d", ret);
277 return LOS_ERRNO_VM_NO_MEMORY;
278 }
279
280 LOS_SpinLockSave(&region->unTypeData.rf.vnode->mapping.list_lock, &intSave);
281 fpage = OsFindGetEntry(&region->unTypeData.rf.vnode->mapping, vmPgFault->pgoff);
282 if (fpage) {//在页高速缓存(page cache)中找到了
283 OsMarkPageDirty(fpage, region, 0, 0);//标记为脏页
284 }
285 LOS_SpinUnlockRestore(&region->unTypeData.rf.vnode->mapping.list_lock, intSave);
286
287 return LOS_OK;
288 }
289 //以下是没有映射到物理地址的处理
290 (VOID)LOS_MuxAcquire(&region->unTypeData.rf.vnode->mapping.mux_lock);
291 ret = region->unTypeData.rf.vmFOps->fault(region, vmPgFault);//函数指针,执行的是g_commVmOps.OsVmmFileFault
292 if (ret == LOS_OK) {
293 paddr = LOS_PaddrQuery(vmPgFault->pageKVaddr);
294 page = LOS_VmPageGet(paddr);
295 /* just in case of page null */
296 if (page != NULL) {
297 LOS_AtomicInc(&page->refCounts);
298 OsCleanPageLocked(page);
299 }
300 ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);
301 if (ret < 0) {
302 VM_ERR("LOS_ArchMmuMap failed. ret=%d", ret);
303 OsDelMapInfo(region, vmPgFault, TRUE);
304 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
305 return LOS_ERRNO_VM_NO_MEMORY;
306 }
307
308 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
309 return LOS_OK;
310 }
311 (VOID)LOS_MuxRelease(&region->unTypeData.rf.vnode->mapping.mux_lock);
312 return ret;
313}
VOID OsMarkPageDirty(LosFilePage *fpage, LosVmMapRegion *region, int off, int len)
if(tv==NULL)
Definition: time.c:430
函数调用图:
这是这个函数的调用关系图:

◆ OsFaultTryFixup()

STATIC VOID OsFaultTryFixup ( ExcContext frame,
VADDR_T  excVaddr,
STATUS_T status 
)

在文件 los_vm_fault.c81 行定义.

82{
83 INT32 tableNum = (__exc_table_end - __exc_table_start) / sizeof(LosExcTable);
85
86 if ((frame->regCPSR & CPSR_MODE_MASK) != CPSR_MODE_USR) {
87 for (int i = 0; i < tableNum; ++i, ++excTable) {
88 if (frame->PC == (UINTPTR)excTable->excAddr) {
89 frame->PC = (UINTPTR)excTable->fixAddr;
90 frame->R2 = (UINTPTR)excVaddr;
91 *status = LOS_OK;
92 return;
93 }
94 }
95 }
96}
signed int INT32
Definition: los_typedef.h:60
unsigned long UINTPTR
Definition: los_typedef.h:68
char __exc_table_end[]
char __exc_table_start[]
UINT32 PC
Definition: los_exc.h:87
UINT32 regCPSR
Definition: los_exc.h:88
UINT32 R2
Definition: los_exc.h:83
VADDR_T fixAddr
Definition: los_vm_fault.h:51
VADDR_T excAddr
Definition: los_vm_fault.h:50
这是这个函数的调用关系图:

◆ OsVmPageFaultHandler()

STATUS_T OsVmPageFaultHandler ( VADDR_T  vaddr,
UINT32  flags,
ExcContext frame 
)
参数
vaddr
flags
frame
返回
STATUS_T

在文件 los_vm_fault.c352 行定义.

353{
354 LosVmSpace *space = LOS_SpaceGet(vaddr);//获取虚拟地址所属空间
355 LosVmMapRegion *region = NULL;
356 STATUS_T status;
357 PADDR_T oldPaddr;
358 PADDR_T newPaddr;
359 VADDR_T excVaddr = vaddr;
360 LosVmPage *newPage = NULL;
361 LosVmPgFault vmPgFault = { 0 };
362
363 if (space == NULL) {
364 VM_ERR("vm space not exists, vaddr: %#x", vaddr);
365 status = LOS_ERRNO_VM_NOT_FOUND;
366 OsFaultTryFixup(frame, excVaddr, &status);
367 return status;
368 }
369
370 if (((flags & VM_MAP_PF_FLAG_USER) != 0) && (!LOS_IsUserAddress(vaddr))) {//地址保护,用户空间不允许跨界访问
371 VM_ERR("user space not allowed to access invalid address: %#x", vaddr);
372 return LOS_ERRNO_VM_ACCESS_DENIED;//拒绝访问
373 }
374
375 (VOID)LOS_MuxAcquire(&space->regionMux);
376 region = LOS_RegionFind(space, vaddr);//通过虚拟地址找到所在线性区
377 if (region == NULL) {
378 VM_ERR("region not exists, vaddr: %#x", vaddr);
379 status = LOS_ERRNO_VM_NOT_FOUND;
380 goto CHECK_FAILED;
381 }
382
383 status = OsVmRegionPermissionCheck(region, flags);
384 if (status != LOS_OK) {
385 status = LOS_ERRNO_VM_ACCESS_DENIED;//拒绝访问
386 goto CHECK_FAILED;
387 }
388
389 if (OomCheckProcess()) {//低内存检查
390 /*
391 * under low memory, when user process request memory allocation
392 * it will fail, and result is LOS_NOK and current user process
393 * will be deleted. memory usage detail will be printed.
394 */
395 status = LOS_ERRNO_VM_NO_MEMORY;
396 goto CHECK_FAILED;
397 }
398
399 vaddr = ROUNDDOWN(vaddr, PAGE_SIZE);//为啥要向下圆整,因为这一页要重新使用,需找到页面基地址
400#ifdef LOSCFG_FS_VFS
401 if (LOS_IsRegionFileValid(region)) {//是否为文件线性区
402 if (region->unTypeData.rf.vnode == NULL) {
403 goto CHECK_FAILED;
404 }
405 vmPgFault.vaddr = vaddr;//虚拟地址
406 vmPgFault.pgoff = ((vaddr - region->range.base) >> PAGE_SHIFT) + region->pgOff;//计算出文件读取位置
407 vmPgFault.flags = flags;
408 vmPgFault.pageKVaddr = NULL;//缺失页初始化没有物理地址
409
410 status = OsDoFileFault(region, &vmPgFault, flags);//缺页处理
411 if (status) {
412 VM_ERR("vm fault error, status=%d", status);
413 goto CHECK_FAILED;
414 }
415 goto DONE;
416 }
417#endif
418 //请求调页:推迟到不能再推迟为止
419 newPage = LOS_PhysPageAlloc();//分配一个新的物理页
420 if (newPage == NULL) {
421 status = LOS_ERRNO_VM_NO_MEMORY;
422 goto CHECK_FAILED;
423 }
424
425 newPaddr = VM_PAGE_TO_PHYS(newPage);//获取物理地址
426 (VOID)memset_s(OsVmPageToVaddr(newPage), PAGE_SIZE, 0, PAGE_SIZE);//获取虚拟地址 清0
427 status = LOS_ArchMmuQuery(&space->archMmu, vaddr, &oldPaddr, NULL);//通过虚拟地址查询老物理地址
428 if (status >= 0) {//已经映射过了,@note_thinking 不是缺页吗,怎么会有页的情况?
429 LOS_ArchMmuUnmap(&space->archMmu, vaddr, 1);//解除映射关系
430 OsPhysSharePageCopy(oldPaddr, &newPaddr, newPage);//将oldPaddr的数据拷贝到newPage
431 /* use old page free the new one */
432 if (newPaddr == oldPaddr) {//新老物理地址一致
433 LOS_PhysPageFree(newPage);//继续使用旧页释放新页
434 newPage = NULL;
435 }
436
437 /* map all of the pages */
438 status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);//重新映射新物理地址
439 if (status < 0) {
440 VM_ERR("failed to map replacement page, status:%d", status);
441 status = LOS_ERRNO_VM_MAP_FAILED;
442 goto VMM_MAP_FAILED;
443 }
444
445 status = LOS_OK;
446 goto DONE;
447 } else {//
448 /* map all of the pages */
449 LOS_AtomicInc(&newPage->refCounts);//引用数自增
450 status = LOS_ArchMmuMap(&space->archMmu, vaddr, newPaddr, 1, region->regionFlags);//映射新物理地址,如此下次就不会缺页了
451 if (status < 0) {
452 VM_ERR("failed to map page, status:%d", status);
453 status = LOS_ERRNO_VM_MAP_FAILED;
454 goto VMM_MAP_FAILED;
455 }
456 }
457
458 status = LOS_OK;
459 goto DONE;
460VMM_MAP_FAILED:
461 if (newPage != NULL) {
462 LOS_PhysPageFree(newPage);
463 }
464CHECK_FAILED:
465 OsFaultTryFixup(frame, excVaddr, &status);
466DONE:
467 (VOID)LOS_MuxRelease(&space->regionMux);
468 return status;
469}
LITE_OS_SEC_TEXT_MINOR BOOL OomCheckProcess(VOID)
Definition: oom.c:124
STATIC VOID OsFaultTryFixup(ExcContext *frame, VADDR_T excVaddr, STATUS_T *status)
Definition: los_vm_fault.c:81
STATIC STATUS_T OsVmRegionPermissionCheck(LosVmMapRegion *region, UINT32 flags)
Definition: los_vm_fault.c:57
STATIC STATUS_T OsDoFileFault(LosVmMapRegion *region, LosVmPgFault *vmPgFault, UINT32 flags)
Definition: los_vm_fault.c:323
BOOL LOS_IsRegionFileValid(LosVmMapRegion *region)
映射类型为文件的线性区是否有效
Definition: los_vm_map.c:512
LosVmSpace * LOS_SpaceGet(VADDR_T vaddr)
获取虚拟地址对应的进程空间结构体指针
Definition: los_vm_map.c:117
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
虚拟地址是否在用户空间
Definition: los_vm_map.h:275
LosVmMapRegion * LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
查找线性区 根据起始地址在进程空间内查找是否存在
Definition: los_vm_map.c:414
缺页结构信息体
Definition: los_vm_map.h:95
UINT32 flags
Definition: los_vm_map.h:96
VADDR_T base
Definition: los_vm_map.h:84
LosVmMapRange range
Definition: los_vm_map.h:123
VM_OFFSET_T pgOff
Definition: los_vm_map.h:124
LosMux regionMux
Definition: los_vm_map.h:149
函数调用图:
这是这个函数的调用关系图:

◆ OsVmRegionPermissionCheck()

STATIC STATUS_T OsVmRegionPermissionCheck ( LosVmMapRegion region,
UINT32  flags 
)

在文件 los_vm_fault.c57 行定义.

58{
59 if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_READ) != VM_MAP_REGION_FLAG_PERM_READ) {
60 VM_ERR("read permission check failed operation flags %x, region flags %x", flags, region->regionFlags);
61 return LOS_NOK;
62 }
63
64 if ((flags & VM_MAP_PF_FLAG_WRITE) == VM_MAP_PF_FLAG_WRITE) {//写入许可
65 if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_WRITE) != VM_MAP_REGION_FLAG_PERM_WRITE) {
66 VM_ERR("write permission check failed operation flags %x, region flags %x", flags, region->regionFlags);
67 return LOS_NOK;
68 }
69 }
70
71 if ((flags & VM_MAP_PF_FLAG_INSTRUCTION) == VM_MAP_PF_FLAG_INSTRUCTION) {//指令
72 if ((region->regionFlags & VM_MAP_REGION_FLAG_PERM_EXECUTE) != VM_MAP_REGION_FLAG_PERM_EXECUTE) {
73 VM_ERR("exec permission check failed operation flags %x, region flags %x", flags, region->regionFlags);
74 return LOS_NOK;
75 }
76 }
77
78 return LOS_OK;
79}
这是这个函数的调用关系图:

变量说明

◆ __exc_table_end

char __exc_table_end[]
extern

◆ __exc_table_start

char __exc_table_start[]
extern