更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_arch_mmu.c
浏览该文件的文档.
1/*!
2 * @file los_arch_mmu.c
3 * @brief 虚实映射其实就是一个建立页表的过程
4 * @link http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-inner-reflect.html
5 * @verbatim
6
7 虚实映射是指系统通过内存管理单元(MMU,Memory Management Unit)将进程空间的虚拟地址与实际的物理地址做映射,
8 并指定相应的访问权限、缓存属性等。程序执行时,CPU访问的是虚拟内存,通过MMU页表条目找到对应的物理内存,
9 并做相应的代码执行或数据读写操作。MMU的映射由页表(Page Table)来描述,其中保存虚拟地址和物理地址的映射关系以及访问权限等。
10 每个进程在创建的时候都会创建一个页表,页表由一个个页表条目(Page Table Entry, PTE)构成,
11 每个页表条目描述虚拟地址区间与物理地址区间的映射关系。MMU中有一块页表缓存,称为快表(TLB, Translation Lookaside Buffers),
12 做地址转换时,MMU首先在TLB中查找,如果找到对应的页表条目可直接进行转换,提高了查询效率。
13
14 虚实映射其实就是一个建立页表的过程。MMU有多级页表,LiteOS-A内核采用二级页表描述进程空间。每个一级页表条目描述符占用4个字节,
15 可表示1MiB的内存空间的映射关系,即1GiB用户空间(LiteOS-A内核中用户空间占用1GiB)的虚拟内存空间需要1024个。系统创建用户进程时,
16 在内存中申请一块4KiB大小的内存块作为一级页表的存储区域,二级页表根据当前进程的需要做动态的内存申请。
17
18 用户程序加载启动时,会将代码段、数据段映射进虚拟内存空间(详细可参考动态加载与链接),此时并没有物理页做实际的映射;
19 程序执行时,如下图粗箭头所示,CPU访问虚拟地址,通过MMU查找是否有对应的物理内存,若该虚拟地址无对应的物理地址则触发缺页异常,
20 内核申请物理内存并将虚实映射关系及对应的属性配置信息写进页表,并把页表条目缓存至TLB,接着CPU可直接通过转换关系访问实际的物理内存;
21 若CPU访问已缓存至TLB的页表条目,无需再访问保存在内存中的页表,可加快查找速度。
22
23 开发流程
24 1. 虚实映射相关接口的使用:
25 通过LOS_ArchMmuMap映射一块物理内存。
26
27 2. 对映射的地址区间做相关操作:
28 通过LOS_ArchMmuQuery可以查询相应虚拟地址区间映射的物理地址区间及映射属性;
29 通过LOS_ArchMmuChangeProt修改映射属性;
30 通过LOS_ArchMmuMove做虚拟地址区间的重映射。
31 3. 通过LOS_ArchMmuUnmap解除映射关系。
32
33 * @endverbatim
34 * @version
35 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
36 * @date 2021-11-17
37 *
38 * @history
39 *
40 */
41/*
42 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
43 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without modification,
46 * are permitted provided that the following conditions are met:
47 *
48 * 1. Redistributions of source code must retain the above copyright notice, this list of
49 * conditions and the following disclaimer.
50 *
51 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
52 * of conditions and the following disclaimer in the documentation and/or other materials
53 * provided with the distribution.
54 *
55 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
56 * to endorse or promote products derived from this software without specific prior written
57 * permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
60 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
61 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
63 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
64 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
65 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
66 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
67 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
68 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
69 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 */
71
72/**
73 * @defgroup los_arch_mmu architecture mmu
74 * @ingroup kernel
75 */
76
77#include "los_arch_mmu.h"
78#include "los_asid.h"
79#include "los_pte_ops.h"
80#include "los_tlb_v6.h"
81#include "los_printf.h"
82#include "los_vm_common.h"
83#include "los_vm_map.h"
84#include "los_vm_boot.h"
86#include "los_process_pri.h"
87
88#ifdef LOSCFG_KERNEL_MMU
89typedef struct {
95
96#define TRY_MAX_TIMES 10
97
98__attribute__((aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS))) \
99 __attribute__((section(".bss.prebss.translation_table"))) UINT8 \
100 g_firstPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS];
101#ifdef LOSCFG_KERNEL_SMP
102__attribute__((aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS))) \
103 __attribute__((section(".bss.prebss.translation_table"))) UINT8 \
104 g_tempPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS];
105UINT8 *g_mmuJumpPageTable = g_tempPageTable;
106#else
107extern CHAR __mmu_ttlb_begin; /* defined in .ld script | 内核临时页表在系统使能mmu到使用虚拟地址运行这段期间使用,其虚拟地址保存在g_mmuJumpPageTable这个指针中*/
108UINT8 *g_mmuJumpPageTable = (UINT8 *)&__mmu_ttlb_begin; /* temp page table, this is only used when system power up | 临时页表,用于系统启动阶段*/
109#endif
110
111STATIC SPIN_LOCK_S *OsGetPteLock(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
112{
113 SPIN_LOCK_S *lock = NULL;
114#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
115 LosVmPage *vmPage = NULL;
116
117 vmPage = OsVmPaddrToPage(paddr);
118 if (vmPage == NULL) {
119 return NULL;
120 }
121 lock = &vmPage->lock;
122#else
123 lock = &archMmu->lock;
124#endif
125
126 LOS_SpinLockSave(lock, intSave);
127 return lock;
128}
129
130STATIC SPIN_LOCK_S *OsGetPte1Lock(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
131{
132 return OsGetPteLock(archMmu, paddr, intSave);
133}
134
135STATIC INLINE VOID OsUnlockPte1(SPIN_LOCK_S *lock, UINT32 intSave)
136{
137 if (lock == NULL) {
138 return;
139 }
140 LOS_SpinUnlockRestore(lock, intSave);
141}
142
143STATIC SPIN_LOCK_S *OsGetPte1LockTmp(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
144{
145 SPIN_LOCK_S *spinLock = NULL;
146#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
147 spinLock = OsGetPteLock(archMmu, paddr, intSave);
148#else
149 (VOID)archMmu;
150 (VOID)paddr;
151 (VOID)intSave;
152#endif
153 return spinLock;
154}
155
156STATIC INLINE VOID OsUnlockPte1Tmp(SPIN_LOCK_S *lock, UINT32 intSave)
157{
158#ifdef LOSCFG_PAGE_TABLE_FINE_LOCK
159 if (lock == NULL) {
160 return;
161 }
162 LOS_SpinUnlockRestore(lock, intSave);
163#else
164 (VOID)lock;
165 (VOID)intSave;
166#endif
167}
168
169STATIC INLINE SPIN_LOCK_S *OsGetPte2Lock(LosArchMmu *archMmu, PTE_T pte1, UINT32 *intSave)
170{
171 PADDR_T pa = MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1);
172 return OsGetPteLock(archMmu, pa, intSave);
173}
174
175STATIC INLINE VOID OsUnlockPte2(SPIN_LOCK_S *lock, UINT32 intSave)
176{
177 return OsUnlockPte1(lock, intSave);
178}
179/// 获取页表基地址
180STATIC INLINE PTE_T *OsGetPte2BasePtr(PTE_T pte1)
181{
182 PADDR_T pa = MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1);
183 return LOS_PaddrToKVaddr(pa);
184}
185
187{
188 return (VADDR_T *)g_firstPageTable;
189}
190
191/// 解除L1表的映射关系
192STATIC INLINE UINT32 OsUnmapL1Invalid(vaddr_t *vaddr, UINT32 *count)
193{
194 UINT32 unmapCount;
195
196 unmapCount = MIN2((MMU_DESCRIPTOR_L1_SMALL_SIZE - (*vaddr % MMU_DESCRIPTOR_L1_SMALL_SIZE)) >>
197 MMU_DESCRIPTOR_L2_SMALL_SHIFT, *count);
198 *vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
199 *count -= unmapCount;
200
201 return unmapCount;
202}
203
204STATIC INT32 OsMapParamCheck(UINT32 flags, VADDR_T vaddr, PADDR_T paddr)
205{
206#if !WITH_ARCH_MMU_PICK_SPOT
207 if (flags & VM_MAP_REGION_FLAG_NS) {
208 /* WITH_ARCH_MMU_PICK_SPOT is required to support NS memory */
209 LOS_Panic("NS mem is not supported\n");
210 }
211#endif
212
213 /* paddr and vaddr must be aligned */
214 if (!MMU_DESCRIPTOR_IS_L2_SIZE_ALIGNED(vaddr) || !MMU_DESCRIPTOR_IS_L2_SIZE_ALIGNED(paddr)) {
215 return LOS_ERRNO_VM_INVALID_ARGS;
216 }
217
218 return 0;
219}
220
221STATIC VOID OsCvtPte2AttsToFlags(PTE_T l1Entry, PTE_T l2Entry, UINT32 *flags)
222{
223 *flags = 0;
224 /* NS flag is only present on L1 entry */
225 if (l1Entry & MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE) {
226 *flags |= VM_MAP_REGION_FLAG_NS;
227 }
228
229 switch (l2Entry & MMU_DESCRIPTOR_L2_TEX_TYPE_MASK) {
230 case MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED:
231 *flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
232 break;
233 case MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE:
234 *flags |= VM_MAP_REGION_FLAG_UNCACHED;
235 break;
236 case MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED:
237 case MMU_DESCRIPTOR_L2_TYPE_DEVICE_NON_SHARED:
238 *flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
239 break;
240 default:
241 break;
242 }
243
244 *flags |= VM_MAP_REGION_FLAG_PERM_READ;
245
246 switch (l2Entry & MMU_DESCRIPTOR_L2_AP_MASK) {
247 case MMU_DESCRIPTOR_L2_AP_P_RO_U_NA:
248 break;
249 case MMU_DESCRIPTOR_L2_AP_P_RW_U_NA:
250 *flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
251 break;
252 case MMU_DESCRIPTOR_L2_AP_P_RO_U_RO:
253 *flags |= VM_MAP_REGION_FLAG_PERM_USER;
254 break;
255 case MMU_DESCRIPTOR_L2_AP_P_RW_U_RW:
256 *flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
257 break;
258 default:
259 break;
260 }
261 if ((l2Entry & MMU_DESCRIPTOR_L2_TYPE_MASK) != MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN) {
262 *flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
263 }
264}
265
266STATIC VOID OsPutL2Table(const LosArchMmu *archMmu, UINT32 l1Index, paddr_t l2Paddr)
267{
268 UINT32 index;
269 PTE_T ttEntry;
270 /* check if any l1 entry points to this l2 table */
271 for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) {
272 ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index];
273 if ((ttEntry & MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) {
274 return;
275 }
276 }
277#ifdef LOSCFG_KERNEL_VM
278 /* we can free this l2 table */
279 LosVmPage *vmPage = LOS_VmPageGet(l2Paddr);
280 if (vmPage == NULL) {
281 LOS_Panic("bad page table paddr %#x\n", l2Paddr);
282 return;
283 }
284
285 LOS_ListDelete(&vmPage->node);
286 LOS_PhysPageFree(vmPage);
287#else
288 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, LOS_PaddrToKVaddr(l2Paddr));
289#endif
290}
291
292STATIC VOID OsTryUnmapL1PTE(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t vaddr, UINT32 scanIndex, UINT32 scanCount)
293{
294 /*
295 * Check if all pages related to this l1 entry are deallocated.
296 * We only need to check pages that we did not clear above starting
297 * from scanIndex and wrapped around SECTION.
298 */
299 UINT32 l1Index;
300 PTE_T *pte2BasePtr = NULL;
301 SPIN_LOCK_S *pte1Lock = NULL;
302 SPIN_LOCK_S *pte2Lock = NULL;
303 UINT32 pte1IntSave;
304 UINT32 pte2IntSave;
305 PTE_T pte1Val;
306 PADDR_T pte1Paddr;
307
308 pte1Paddr = OsGetPte1Paddr(archMmu->physTtb, vaddr);
309 pte2Lock = OsGetPte2Lock(archMmu, *l1Entry, &pte2IntSave);
310 if (pte2Lock == NULL) {
311 return;
312 }
313 pte2BasePtr = OsGetPte2BasePtr(*l1Entry);
314 if (pte2BasePtr == NULL) {
315 OsUnlockPte2(pte2Lock, pte2IntSave);
316 return;
317 }
318
319 while (scanCount) {
320 if (scanIndex == MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
321 scanIndex = 0;
322 }
323 if (pte2BasePtr[scanIndex++]) {
324 break;
325 }
326 scanCount--;
327 }
328
329 if (!scanCount) {
330 /*
331 * The pte1 of kprocess is placed in kernel image when compiled. So the pte1Lock will be null.
332 * There is no situation to simultaneous access the pte1 of kprocess.
333 */
334 pte1Lock = OsGetPte1LockTmp(archMmu, pte1Paddr, &pte1IntSave);
335 if (!OsIsPte1PageTable(*l1Entry)) {
336 OsUnlockPte1Tmp(pte1Lock, pte1IntSave);
337 OsUnlockPte2(pte2Lock, pte2IntSave);
338 return;
339 }
340 pte1Val = *l1Entry;
341 /* we can kill l1 entry */
342 OsClearPte1(l1Entry);
343 l1Index = OsGetPte1Index(vaddr);
344 OsArmInvalidateTlbMvaNoBarrier(l1Index << MMU_DESCRIPTOR_L1_SMALL_SHIFT);
345
346 /* try to free l2 page itself */
347 OsPutL2Table(archMmu, l1Index, MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1Val));
348 OsUnlockPte1Tmp(pte1Lock, pte1IntSave);
349 }
350 OsUnlockPte2(pte2Lock, pte2IntSave);
351}
352
354{
355 UINT32 mmuFlags = 0;
356
357 switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
358 case VM_MAP_REGION_FLAG_CACHED:
359 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
360#ifdef LOSCFG_KERNEL_SMP
361 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_SHAREABLE;
362#endif
363 break;
364 case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
365 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED;
366 break;
367 case VM_MAP_REGION_FLAG_UNCACHED:
368 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE;
369 break;
370 case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
371 mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED;
372 break;
373 default:
374 return LOS_ERRNO_VM_INVALID_ARGS;
375 }
376 return mmuFlags;
377}
378
380{
381 UINT32 mmuFlags = 0;
382
383 switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
384 case 0:
385 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
386 break;
387 case VM_MAP_REGION_FLAG_PERM_READ:
388 case VM_MAP_REGION_FLAG_PERM_USER:
389 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_NA;
390 break;
391 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
392 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_RO;
393 break;
394 case VM_MAP_REGION_FLAG_PERM_WRITE:
395 case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
396 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_NA;
397 break;
398 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
399 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
400 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_RW;
401 break;
402 default:
403 break;
404 }
405 return mmuFlags;
406}
407
408/* convert user level mmu flags to L1 descriptors flags */
410{
411 UINT32 mmuFlags;
412
413 mmuFlags = OsCvtSecCacheFlagsToMMUFlags(flags);
414 if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
415 return mmuFlags;
416 }
417
418 mmuFlags |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT;
419
420 mmuFlags |= OsCvtSecAccessFlagsToMMUFlags(flags);
421
422 if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
423 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_XN;
424 }
425
426 if (flags & VM_MAP_REGION_FLAG_NS) {
427 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_SECURE;
428 }
429
430 if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
431 mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_GLOBAL;
432 }
433
434 return mmuFlags;
435}
436
437STATIC VOID OsCvtSecAttsToFlags(PTE_T l1Entry, UINT32 *flags)
438{
439 *flags = 0;
440 if (l1Entry & MMU_DESCRIPTOR_L1_SECTION_NON_SECURE) {
441 *flags |= VM_MAP_REGION_FLAG_NS;
442 }
443
444 switch (l1Entry & MMU_DESCRIPTOR_L1_TEX_TYPE_MASK) {
445 case MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED:
446 *flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
447 break;
448 case MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE:
449 *flags |= VM_MAP_REGION_FLAG_UNCACHED;
450 break;
451 case MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED:
452 case MMU_DESCRIPTOR_L1_TYPE_DEVICE_NON_SHARED:
453 *flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
454 break;
455 default:
456 break;
457 }
458
459 *flags |= VM_MAP_REGION_FLAG_PERM_READ;
460
461 switch (l1Entry & MMU_DESCRIPTOR_L1_AP_MASK) {
462 case MMU_DESCRIPTOR_L1_AP_P_RO_U_NA:
463 break;
464 case MMU_DESCRIPTOR_L1_AP_P_RW_U_NA:
465 *flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
466 break;
467 case MMU_DESCRIPTOR_L1_AP_P_RO_U_RO:
468 *flags |= VM_MAP_REGION_FLAG_PERM_USER;
469 break;
470 case MMU_DESCRIPTOR_L1_AP_P_RW_U_RW:
471 *flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
472 break;
473 default:
474 break;
475 }
476
477 if (!(l1Entry & MMU_DESCRIPTOR_L1_SECTION_XN)) {
478 *flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
479 }
480}
481
482STATIC UINT32 OsUnmapL2PTE(LosArchMmu *archMmu, PTE_T *pte1, vaddr_t vaddr, UINT32 *count)
483{
484 UINT32 unmapCount;
485 UINT32 pte2Index;
486 UINT32 intSave;
487 PTE_T *pte2BasePtr = NULL;
488 SPIN_LOCK_S *lock = NULL;
489
490 pte2Index = OsGetPte2Index(vaddr);
491 unmapCount = MIN2(MMU_DESCRIPTOR_L2_NUMBERS_PER_L1 - pte2Index, *count);
492
493 lock = OsGetPte2Lock(archMmu, *pte1, &intSave);
494 if (lock == NULL) {
495 return unmapCount;
496 }
497
498 pte2BasePtr = OsGetPte2BasePtr(*pte1);
499 if (pte2BasePtr == NULL) {
500 OsUnlockPte2(lock, intSave);
501 return unmapCount;
502 }
503
504 /* unmap page run */
505 OsClearPte2Continuous(&pte2BasePtr[pte2Index], unmapCount);
506
507 /* invalidate tlb */
508 OsArmInvalidateTlbMvaRangeNoBarrier(vaddr, unmapCount);
509 OsUnlockPte2(lock, intSave);
510
511 *count -= unmapCount;
512 return unmapCount;
513}
514
515STATIC UINT32 OsUnmapSection(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t *vaddr, UINT32 *count)
516{
517 UINT32 intSave;
518 PADDR_T pte1Paddr;
519 SPIN_LOCK_S *lock = NULL;
520
521 pte1Paddr = OsGetPte1Paddr(archMmu->physTtb, *vaddr);
522 lock = OsGetPte1Lock(archMmu, pte1Paddr, &intSave);
523 if (!OsIsPte1Section(*l1Entry)) {
524 OsUnlockPte1(lock, intSave);
525 return 0;
526 }
527 OsClearPte1(OsGetPte1Ptr((PTE_T *)archMmu->virtTtb, *vaddr));
529 OsUnlockPte1(lock, intSave);
530
531 *vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
532 *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
533
534 return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
535}
536
538{
539#ifdef LOSCFG_KERNEL_VM
540 if (OsAllocAsid(&archMmu->asid) != LOS_OK) {//分配一个asid,ASID可用来唯一标识进程空间
541 VM_ERR("alloc arch mmu asid failed");//地址空间标识码(address-space identifier,ASID)为CP15协处理器 C13寄存器
542 return FALSE;
543 }
544#endif
545
546#ifndef LOSCFG_PAGE_TABLE_FINE_LOCK
547 LOS_SpinInit(&archMmu->lock);
548#endif
549 LOS_ListInit(&archMmu->ptList);//初始化页表,双循环进程所有物理页框 LOS_ListAdd(&processCB->vmSpace->archMmu.ptList, &(vmPage->node));
550 archMmu->virtTtb = virtTtb;//为L1页表在内存位置 section(".bss.prebss.translation_table") UINT8 g_firstPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS]
551 archMmu->physTtb = (VADDR_T)(UINTPTR)virtTtb - KERNEL_ASPACE_BASE + SYS_MEM_BASE;// TTB寄存器是CP15协处理器的C2寄存器,存页表的基地址
552 //SYS_MEM_BASE = 0x80000000 KERNEL_ASPACE_BASE = 0x40000000 见于 ..\vendor\hi3516dv300\config\board\include\board.h
553 //archMmu->physTtb = (VADDR_T)(UINTPTR)virtTtb + 0x40000000;
554 return TRUE;
555}
556
557
558/*!
559 * @brief LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。
560 * 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
561 * @param archMmu
562 * @param flags
563 * @param paddr
564 * @param vaddr
565 * @return
566 *
567 * @see
568 */
569STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
570{//archMmu->virtTtb:转换表基地址
571 PTE_T l1Entry = OsGetPte1(archMmu->virtTtb, vaddr);//获取PTE vaddr右移20位 得到L1描述子地址
572 PTE_T l2Entry;
573 PTE_T* l2Base = NULL;
574
575 if (OsIsPte1Invalid(l1Entry)) {//判断L1描述子地址是否有效
576 return LOS_ERRNO_VM_NOT_FOUND;//无效返回虚拟地址未查询到
577 } else if (OsIsPte1Section(l1Entry)) {// section页表项: l1Entry低二位是否为 10
578 if (paddr != NULL) {//物理地址 = 节基地址(section页表项的高12位) + 虚拟地址低20位
579 *paddr = MMU_DESCRIPTOR_L1_SECTION_ADDR(l1Entry) + (vaddr & (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1));
580 }
581
582 if (flags != NULL) {
583 OsCvtSecAttsToFlags(l1Entry, flags);//获取虚拟内存的flag信息
584 }
585 } else if (OsIsPte1PageTable(l1Entry)) {//PAGE_TABLE页表项: l1Entry低二位是否为 01
586 l2Base = OsGetPte2BasePtr(l1Entry);//获取L2转换表基地址
587 if (l2Base == NULL) {
588 return LOS_ERRNO_VM_NOT_FOUND;
589 }
590 l2Entry = OsGetPte2(l2Base, vaddr);//获取L2描述子地址
591 if (OsIsPte2SmallPage(l2Entry) || OsIsPte2SmallPageXN(l2Entry)) {
592 if (paddr != NULL) {//物理地址 = 小页基地址(L2页表项的高20位) + 虚拟地址低12位
593 *paddr = MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(l2Entry) + (vaddr & (MMU_DESCRIPTOR_L2_SMALL_SIZE - 1));
594 }
595
596 if (flags != NULL) {
597 OsCvtPte2AttsToFlags(l1Entry, l2Entry, flags);//获取虚拟内存的flag信息
598 }
599 } else if (OsIsPte2LargePage(l2Entry)) {//鸿蒙目前暂不支持64K大页,未来手机版应该会支持。
600 LOS_Panic("%s %d, large page unimplemented\n", __FUNCTION__, __LINE__);
601 } else {
602 return LOS_ERRNO_VM_NOT_FOUND;
603 }
604 }
605
606 return LOS_OK;
607}
608
609/*!
610 * @brief LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
611 *
612 * @param archMmu
613 * @param count
614 * @param vaddr
615 * @return
616 *
617 * @see
618 */
619STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
620{
621 PTE_T *l1Entry = NULL;
622 INT32 unmapped = 0;
623 UINT32 unmapCount = 0;
624 INT32 tryTime = TRY_MAX_TIMES;
625
626 while (count > 0) {
627 l1Entry = OsGetPte1Ptr(archMmu->virtTtb, vaddr);//获取L1表
628 if (OsIsPte1Invalid(*l1Entry)) {//L1表是否有效
629 unmapCount = OsUnmapL1Invalid(&vaddr, &count);//取消L1表内的映射
630 } else if (OsIsPte1Section(*l1Entry)) {
631 if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(vaddr) && count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
632 unmapCount = OsUnmapSection(archMmu, l1Entry, &vaddr, &count);
633 } else {
634 LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
635 }
636 } else if (OsIsPte1PageTable(*l1Entry)) {
637 unmapCount = OsUnmapL2PTE(archMmu, l1Entry, vaddr, &count);//取消L2表的映射
638 OsTryUnmapL1PTE(archMmu, l1Entry, vaddr, OsGetPte2Index(vaddr) + unmapCount,
639 MMU_DESCRIPTOR_L2_NUMBERS_PER_L1);
640 vaddr += unmapCount << MMU_DESCRIPTOR_L2_SMALL_SHIFT;
641 } else {
642 LOS_Panic("%s %d, unimplemented\n", __FUNCTION__, __LINE__);
643 }
644 tryTime = (unmapCount == 0) ? (tryTime - 1) : tryTime;
645 if (tryTime == 0) {
646 return LOS_ERRNO_VM_FAULT;
647 }
648 unmapped += unmapCount;
649 }
651 return unmapped;
652}
653
654/*!
655 * @brief OsMapSection section页表格式项映射
656 *
657 * @param archMmu
658 * @param count
659 * @param flags
660 * @param paddr
661 * @param vaddr
662 * @return
663 *
664 * @see
665 */
666STATIC UINT32 OsMapSection(MmuMapInfo *mmuMapInfo, UINT32 *count)
667{
668 UINT32 mmuFlags = 0;
669 UINT32 intSave;
670 PADDR_T pte1Paddr;
671 SPIN_LOCK_S *lock = NULL;
672
673 mmuFlags |= OsCvtSecFlagsToAttrs(*mmuMapInfo->flags);
674 pte1Paddr = OsGetPte1Paddr(mmuMapInfo->archMmu->physTtb, *mmuMapInfo->vaddr);
675 lock = OsGetPte1Lock(mmuMapInfo->archMmu, pte1Paddr, &intSave);
676 OsSavePte1(OsGetPte1Ptr(mmuMapInfo->archMmu->virtTtb, *mmuMapInfo->vaddr),
677 OsTruncPte1(*mmuMapInfo->paddr) | mmuFlags | MMU_DESCRIPTOR_L1_TYPE_SECTION);
678 OsUnlockPte1(lock, intSave);
679 *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
680 *mmuMapInfo->vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
681 *mmuMapInfo->paddr += MMU_DESCRIPTOR_L1_SMALL_SIZE;
682
683 return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
684}
685/// 获取L2页表,分配L2表(需物理内存)
686STATIC STATUS_T OsGetL2Table(LosArchMmu *archMmu, UINT32 l1Index, paddr_t *ppa)
687{
688 UINT32 index;
689 PTE_T ttEntry;
690 VADDR_T *kvaddr = NULL;
691 UINT32 l2Offset = (MMU_DESCRIPTOR_L2_SMALL_SIZE / MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) *
692 (l1Index & (MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE - 1));//计算偏移量,因为一个L2表最大是1K,而一个物理页框是4K,内核不铺张浪费把4个L2表放在一个页框中
693 /* lookup an existing l2 page table *///查询已存在的L2表
694 for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) {
695 ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index];
696 if ((ttEntry & MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) {
697 *ppa = (PADDR_T)ROUNDDOWN(MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(ttEntry), MMU_DESCRIPTOR_L2_SMALL_SIZE) +
698 l2Offset;
699 return LOS_OK;
700 }
701 }
702
703#ifdef LOSCFG_KERNEL_VM
704 /* not found: allocate one (paddr) */
705 LosVmPage *vmPage = LOS_PhysPageAlloc();
706 if (vmPage == NULL) {
707 VM_ERR("have no memory to save l2 page");
708 return LOS_ERRNO_VM_NO_MEMORY;
709 }
710 LOS_ListAdd(&archMmu->ptList, &vmPage->node);
711 kvaddr = OsVmPageToVaddr(vmPage);
712#else
713 kvaddr = LOS_MemAlloc(OS_SYS_MEM_ADDR, MMU_DESCRIPTOR_L2_SMALL_SIZE);
714 if (kvaddr == NULL) {
715 VM_ERR("have no memory to save l2 page");
716 return LOS_ERRNO_VM_NO_MEMORY;
717 }
718#endif
719 (VOID)memset_s(kvaddr, MMU_DESCRIPTOR_L2_SMALL_SIZE, 0, MMU_DESCRIPTOR_L2_SMALL_SIZE);
720
721 /* get physical address */
722 *ppa = OsKVaddrToPaddr((VADDR_T)kvaddr) + l2Offset;
723 return LOS_OK;
724}
725
727{
728 UINT32 mmuFlags = 0;
729
730 switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
731 case VM_MAP_REGION_FLAG_CACHED:
732#ifdef LOSCFG_KERNEL_SMP
733 mmuFlags |= MMU_DESCRIPTOR_L2_SHAREABLE;
734#endif
735 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
736 break;
737 case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
738 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED;
739 break;
740 case VM_MAP_REGION_FLAG_UNCACHED:
741 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE;
742 break;
743 case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
744 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED;
745 break;
746 default:
747 return LOS_ERRNO_VM_INVALID_ARGS;
748 }
749 return mmuFlags;
750}
751
753{
754 UINT32 mmuFlags = 0;
755
756 switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
757 case 0:
758 mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
759 break;
760 case VM_MAP_REGION_FLAG_PERM_READ:
761 case VM_MAP_REGION_FLAG_PERM_USER:
762 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_NA;
763 break;
764 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
765 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_RO;
766 break;
767 case VM_MAP_REGION_FLAG_PERM_WRITE:
768 case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
769 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_NA;
770 break;
771 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
772 case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
773 mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_RW;
774 break;
775 default:
776 break;
777 }
778 return mmuFlags;
779}
780
781/* convert user level mmu flags to L2 descriptors flags */
783{
784 UINT32 mmuFlags;
785
786 mmuFlags = OsCvtPte2CacheFlagsToMMUFlags(flags);
787 if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
788 return mmuFlags;
789 }
790
791 mmuFlags |= OsCvtPte2AccessFlagsToMMUFlags(flags);
792
793 if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
794 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN;
795 } else {
796 mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE;
797 }
798
799 if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
800 mmuFlags |= MMU_DESCRIPTOR_L2_NON_GLOBAL;
801 }
802
803 return mmuFlags;
804}
805
806STATIC UINT32 OsMapL1PTE(MmuMapInfo *mmuMapInfo, PTE_T *l1Entry, UINT32 *count)
807{
808 PADDR_T pte2Base = 0;
809 PADDR_T pte1Paddr;
810 SPIN_LOCK_S *pte1Lock = NULL;
811 SPIN_LOCK_S *pte2Lock = NULL;
812 PTE_T *pte2BasePtr = NULL;
813 UINT32 saveCounts, archFlags, pte1IntSave, pte2IntSave;
814
815 pte1Paddr = OsGetPte1Paddr(mmuMapInfo->archMmu->physTtb, *mmuMapInfo->vaddr);
816 pte1Lock = OsGetPte1Lock(mmuMapInfo->archMmu, pte1Paddr, &pte1IntSave);
817 if (!OsIsPte1Invalid(*l1Entry)) {
818 OsUnlockPte1(pte1Lock, pte1IntSave);
819 return 0;
820 }
821 if (OsGetL2Table(mmuMapInfo->archMmu, OsGetPte1Index(*mmuMapInfo->vaddr), &pte2Base) != LOS_OK) {
822 LOS_Panic("%s %d, failed to allocate pagetable\n", __FUNCTION__, __LINE__);
823 }
824
825 *l1Entry = pte2Base | MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE;
826 if (*mmuMapInfo->flags & VM_MAP_REGION_FLAG_NS) {
827 *l1Entry |= MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE;
828 }
829 *l1Entry &= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_MASK;
830 *l1Entry |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT; // use client AP
831 OsSavePte1(OsGetPte1Ptr(mmuMapInfo->archMmu->virtTtb, *mmuMapInfo->vaddr), *l1Entry);
832 OsUnlockPte1(pte1Lock, pte1IntSave);
833
834 pte2Lock = OsGetPte2Lock(mmuMapInfo->archMmu, *l1Entry, &pte2IntSave);
835 if (pte2Lock == NULL) {
836 LOS_Panic("pte2 should not be null!\n");
837 }
838 pte2BasePtr = (PTE_T *)LOS_PaddrToKVaddr(pte2Base);
839
840 /* compute the arch flags for L2 4K pages */
841 archFlags = OsCvtPte2FlagsToAttrs(*mmuMapInfo->flags);
842 saveCounts = OsSavePte2Continuous(pte2BasePtr, OsGetPte2Index(*mmuMapInfo->vaddr), *mmuMapInfo->paddr | archFlags,
843 *count);
844 OsUnlockPte2(pte2Lock, pte2IntSave);
845 *mmuMapInfo->paddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
846 *mmuMapInfo->vaddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
847 *count -= saveCounts;
848 return saveCounts;
849}
850
851STATIC UINT32 OsMapL2PageContinous(MmuMapInfo *mmuMapInfo, PTE_T *pte1, UINT32 *count)
852{
853 PTE_T *pte2BasePtr = NULL;
854 UINT32 archFlags;
855 UINT32 saveCounts;
856 UINT32 intSave;
857 SPIN_LOCK_S *lock = NULL;
858
859 lock = OsGetPte2Lock(mmuMapInfo->archMmu, *pte1, &intSave);
860 if (lock == NULL) {
861 return 0;
862 }
863 pte2BasePtr = OsGetPte2BasePtr(*pte1);
864 if (pte2BasePtr == NULL) {
865 OsUnlockPte2(lock, intSave);
866 return 0;
867 }
868
869 /* compute the arch flags for L2 4K pages */
870 archFlags = OsCvtPte2FlagsToAttrs(*mmuMapInfo->flags);
871 saveCounts = OsSavePte2Continuous(pte2BasePtr, OsGetPte2Index(*mmuMapInfo->vaddr), *mmuMapInfo->paddr | archFlags,
872 *count);
873 OsUnlockPte2(lock, intSave);
874 *mmuMapInfo->paddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
875 *mmuMapInfo->vaddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT);
876 *count -= saveCounts;
877 return saveCounts;
878}
879/*!
880 * @brief LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间
881 * 所谓的map就是生成L1,L2页表项的过程
882 * @param archMmu
883 * @param count
884 * @param flags
885 * @param paddr
886 * @param vaddr
887 * @return
888 *
889 * @see
890 */
891status_t LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
892{
893 PTE_T *l1Entry = NULL;
894 UINT32 saveCounts = 0;
895 INT32 mapped = 0;
896 INT32 tryTime = TRY_MAX_TIMES;
897 INT32 checkRst;
898 MmuMapInfo mmuMapInfo = {
899 .archMmu = archMmu,
900 .vaddr = &vaddr,
901 .paddr = &paddr,
902 .flags = &flags,
903 };
904
905 checkRst = OsMapParamCheck(flags, vaddr, paddr);//检查参数
906 if (checkRst < 0) {
907 return checkRst;
908 }
909
910 /* see what kind of mapping we can use */
911 while (count > 0) {
912 if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(*mmuMapInfo.vaddr) &&
913 MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(*mmuMapInfo.paddr) &&
914 count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) {
915 /* compute the arch flags for L1 sections cache, r ,w ,x, domain and type */
916 saveCounts = OsMapSection(&mmuMapInfo, &count);
917 } else {
918 /* have to use a L2 mapping, we only allocate 4KB for L1, support 0 ~ 1GB */
919 l1Entry = OsGetPte1Ptr(archMmu->virtTtb, *mmuMapInfo.vaddr);
920 if (OsIsPte1Invalid(*l1Entry)) {
921 saveCounts = OsMapL1PTE(&mmuMapInfo, l1Entry, &count);
922 } else if (OsIsPte1PageTable(*l1Entry)) {
923 saveCounts = OsMapL2PageContinous(&mmuMapInfo, l1Entry, &count);
924 } else {
925 LOS_Panic("%s %d, unimplemented tt_entry %x\n", __FUNCTION__, __LINE__, l1Entry);
926 }
927 }
928 mapped += saveCounts;
929 tryTime = (saveCounts == 0) ? (tryTime - 1) : tryTime;
930 if (tryTime == 0) {
931 return LOS_ERRNO_VM_TIMED_OUT;
932 }
933 }
934
935 return mapped;
936}
937
938/*!
939 * @brief LOS_ArchMmuChangeProt 修改进程空间虚拟地址区间的映射属性
940 * 改变内存段的访问权限,例如: 读/写/可执行/不可用 ==
941 * @param archMmu
942 * @param count
943 * @param flags
944 * @param vaddr
945 * @return
946 *
947 * @see
948 */
949STATUS_T LOS_ArchMmuChangeProt(LosArchMmu *archMmu, VADDR_T vaddr, size_t count, UINT32 flags)
950{
951 STATUS_T status;
952 PADDR_T paddr = 0;
953
954 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
955 VM_ERR("invalid args: archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
956 return LOS_NOK;
957 }
958
959 while (count > 0) {
960 count--;
961 status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);//1. 先查出物理地址
962 if (status != LOS_OK) {
963 vaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
964 continue;
965 }
966
967 status = LOS_ArchMmuUnmap(archMmu, vaddr, 1);//2. 取消原有映射
968 if (status < 0) {
969 VM_ERR("invalid args:aspace %p, vaddr %p, count %d", archMmu, vaddr, count);
970 return LOS_NOK;
971 }
972
973 status = LOS_ArchMmuMap(archMmu, vaddr, paddr, 1, flags);//3. 重新映射 虚实地址
974 if (status < 0) {
975 VM_ERR("invalid args:aspace %p, vaddr %p, count %d",
976 archMmu, vaddr, count);
977 return LOS_NOK;
978 }
979 vaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
980 }
981 return LOS_OK;
982}
983
984/*!
985 * @brief LOS_ArchMmuMove 将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。
986 *
987 * @param archMmu
988 * @param count
989 * @param flags
990 * @param newVaddr
991 * @param oldVaddr
992 * @return
993 *
994 * @see
995 */
996STATUS_T LOS_ArchMmuMove(LosArchMmu *archMmu, VADDR_T oldVaddr, VADDR_T newVaddr, size_t count, UINT32 flags)
997{
998 STATUS_T status;
999 PADDR_T paddr = 0;
1000
1001 if ((archMmu == NULL) || (oldVaddr == 0) || (newVaddr == 0) || (count == 0)) {
1002 VM_ERR("invalid args: archMmu %p, oldVaddr %p, newVaddr %p, count %d",
1003 archMmu, oldVaddr, newVaddr, count);
1004 return LOS_NOK;
1005 }
1006
1007 while (count > 0) {
1008 count--;
1009 status = LOS_ArchMmuQuery(archMmu, oldVaddr, &paddr, NULL);
1010 if (status != LOS_OK) {
1011 oldVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1012 newVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1013 continue;
1014 }
1015 // we need to clear the mapping here and remain the phy page.
1016 status = LOS_ArchMmuUnmap(archMmu, oldVaddr, 1);
1017 if (status < 0) {
1018 VM_ERR("invalid args: archMmu %p, vaddr %p, count %d",
1019 archMmu, oldVaddr, count);
1020 return LOS_NOK;
1021 }
1022
1023 status = LOS_ArchMmuMap(archMmu, newVaddr, paddr, 1, flags);
1024 if (status < 0) {
1025 VM_ERR("invalid args:archMmu %p, old_vaddr %p, new_addr %p, count %d",
1026 archMmu, oldVaddr, newVaddr, count);
1027 return LOS_NOK;
1028 }
1029 oldVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1030 newVaddr += MMU_DESCRIPTOR_L2_SMALL_SIZE;
1031 }
1032
1033 return LOS_OK;
1034}
1035
1036/*!
1037 * @brief LOS_ArchMmuContextSwitch 切换MMU上下文
1038 *
1039 * @param archMmu
1040 * @return
1041 *
1042 * @see
1043 */
1045{
1046 UINT32 ttbr;//B4.1.153 TTBCR, Translation Table Base Control Register,
1047 UINT32 ttbcr = OsArmReadTtbcr();//读取TTB寄存器的状态值
1048 if (archMmu) {
1049 ttbr = MMU_TTBRx_FLAGS | (archMmu->physTtb);//提供进程的映射页表地址,切换MMU代表要换进程,同一进程的线程切换并不需要切MMU
1050 /* enable TTBR0 */
1051 ttbcr &= ~MMU_DESCRIPTOR_TTBCR_PD0;//使能TTBR0 B4.1.154 TTBR0, Translation Table Base Register 0
1052 } else {
1053 ttbr = 0;
1054 /* disable TTBR0 */
1055 ttbcr |= MMU_DESCRIPTOR_TTBCR_PD0;//禁用TTBR0
1056 }
1057
1058#ifdef LOSCFG_KERNEL_VM
1059 /* from armv7a arm B3.10.4, we should do synchronization changes of ASID and TTBR. */
1060 OsArmWriteContextidr(LOS_GetKVmSpace()->archMmu.asid);//这里先把asid切到内核空间的ID
1061 ISB; //指令必须同步 ,清楚流水线中未执行指令
1062#endif
1063 OsArmWriteTtbr0(ttbr);//通过r0寄存器将进程页面基址写入TTB
1064 ISB;
1065 OsArmWriteTtbcr(ttbcr);//写入TTB状态位
1066 ISB;
1067#ifdef LOSCFG_KERNEL_VM
1068 if (archMmu) {
1069 OsArmWriteContextidr(archMmu->asid);//通过R0寄存器写入进程标识符至C13寄存器
1070 ISB; // 可查看 鸿蒙内核源码分析(优雅的宏篇)
1071 }
1072#endif
1073}
1074
1075/*!
1076 * @brief LOS_ArchMmuDestroy 销毁MMU 和 initMmu 相呼应,释放页表页
1077 *
1078 * @param archMmu
1079 * @return
1080 *
1081 * @see
1082 */
1084{
1085#ifdef LOSCFG_KERNEL_VM
1086 LosVmPage *page = NULL;
1087 /* free all of the pages allocated in archMmu->ptList */
1088 while ((page = LOS_ListRemoveHeadType(&archMmu->ptList, LosVmPage, node)) != NULL) {
1089 LOS_PhysPageFree(page);//释放物理页
1090 }
1091
1092 OsArmWriteTlbiasidis(archMmu->asid);
1093 OsFreeAsid(archMmu->asid);//释放asid
1094#endif
1095 return LOS_OK;
1096}
1097/// 切换临时页表
1098STATIC VOID OsSwitchTmpTTB(VOID)
1099{
1100 PTE_T *tmpTtbase = NULL;
1101 errno_t err;
1102 LosVmSpace *kSpace = LOS_GetKVmSpace();
1103
1104 /* ttbr address should be 16KByte align | 页表应该 16Kb对齐,因为 TTB寄存器的低14位为 0 */
1105 tmpTtbase = LOS_MemAllocAlign(m_aucSysMem0, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
1106 MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);//分配页表
1107 if (tmpTtbase == NULL) {
1108 VM_ERR("memory alloc failed");
1109 return;
1110 }
1111
1112 kSpace->archMmu.virtTtb = tmpTtbase;
1113 err = memcpy_s(kSpace->archMmu.virtTtb, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
1114 g_firstPageTable, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);
1115 if (err != EOK) {
1116 (VOID)LOS_MemFree(m_aucSysMem0, tmpTtbase);
1117 kSpace->archMmu.virtTtb = (VADDR_T *)g_firstPageTable;
1118 VM_ERR("memcpy failed, errno: %d", err);
1119 return;
1120 }
1121 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
1122 OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);
1123 ISB;
1124}
1125
1126/// 设置内核空间段属性,可看出内核空间是固定映射到物理地址
1127STATIC VOID OsSetKSectionAttr(UINTPTR virtAddr, BOOL uncached)
1128{
1129 UINT32 offset = virtAddr - KERNEL_VMM_BASE;
1130 /* every section should be page aligned */
1131 UINTPTR textStart = (UINTPTR)&__text_start + offset;
1132 UINTPTR textEnd = (UINTPTR)&__text_end + offset;
1133 UINTPTR rodataStart = (UINTPTR)&__rodata_start + offset;
1134 UINTPTR rodataEnd = (UINTPTR)&__rodata_end + offset;
1135 UINTPTR ramDataStart = (UINTPTR)&__ram_data_start + offset;
1136 UINTPTR bssEnd = (UINTPTR)&__bss_end + offset;
1137 UINT32 bssEndBoundary = ROUNDUP(bssEnd, MB);
1138 LosArchMmuInitMapping mmuKernelMappings[] = {//初始化映射关系
1139 { //映射代码区
1140 .phys = SYS_MEM_BASE + textStart - virtAddr,
1141 .virt = textStart,//内核代码区
1142 .size = ROUNDUP(textEnd - textStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//代码区大小
1143 .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE,//代码段只读,可执行
1144 .name = "kernel_text"
1145 },
1146 { //映射只读数据
1147 .phys = SYS_MEM_BASE + rodataStart - virtAddr,
1148 .virt = rodataStart,//内核常量区
1149 .size = ROUNDUP(rodataEnd - rodataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),//4K对齐
1150 .flags = VM_MAP_REGION_FLAG_PERM_READ,//常量段只读
1151 .name = "kernel_rodata"
1152 },
1153 { //映射全局未初始化区
1154 .phys = SYS_MEM_BASE + ramDataStart - virtAddr,
1155 .virt = ramDataStart,
1156 .size = ROUNDUP(bssEndBoundary - ramDataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
1157 .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE,//全局变量区可读可写
1158 .name = "kernel_data_bss"
1159 }
1160 };
1161 LosVmSpace *kSpace = LOS_GetKVmSpace();//获取内核空间
1162 status_t status;
1163 UINT32 length;
1164 INT32 i;
1165 LosArchMmuInitMapping *kernelMap = NULL;//内核映射
1166 UINT32 kmallocLength;
1167 UINT32 flags;
1168
1169 /* use second-level mapping of default READ and WRITE | 使用二级映射*/
1170 kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;//__attribute__((section(".bss.prebss.translation_table"))) UINT8 g_firstPageTable[MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS];
1171 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);//通过TTB虚拟地址查询TTB物理地址
1172 status = LOS_ArchMmuUnmap(&kSpace->archMmu, virtAddr,
1173 (bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT);
1174 if (status != ((bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1175 VM_ERR("unmap failed, status: %d", status);
1176 return;
1177 }
1178
1179 flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE | VM_MAP_REGION_FLAG_PERM_EXECUTE;
1180 if (uncached) {
1181 flags |= VM_MAP_REGION_FLAG_UNCACHED;
1182 }
1183 status = LOS_ArchMmuMap(&kSpace->archMmu, virtAddr, SYS_MEM_BASE,
1184 (textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
1185 flags);
1186 if (status != ((textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1187 VM_ERR("mmap failed, status: %d", status);
1188 return;
1189 }
1190
1191 length = sizeof(mmuKernelMappings) / sizeof(LosArchMmuInitMapping);
1192 for (i = 0; i < length; i++) {
1193 kernelMap = &mmuKernelMappings[i];
1194 if (uncached) {
1195 kernelMap->flags |= VM_MAP_REGION_FLAG_UNCACHED;
1196 }
1197 status = LOS_ArchMmuMap(&kSpace->archMmu, kernelMap->virt, kernelMap->phys,
1198 kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT, kernelMap->flags);
1199 if (status != (kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1200 VM_ERR("mmap failed, status: %d", status);
1201 return;
1202 }
1203 LOS_VmSpaceReserve(kSpace, kernelMap->size, kernelMap->virt);//保留区
1204 }
1205 //将剩余空间映射好
1206 kmallocLength = virtAddr + SYS_MEM_SIZE_DEFAULT - bssEndBoundary;
1207 flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE;
1208 if (uncached) {
1209 flags |= VM_MAP_REGION_FLAG_UNCACHED;
1210 }
1211 status = LOS_ArchMmuMap(&kSpace->archMmu, bssEndBoundary,
1212 SYS_MEM_BASE + bssEndBoundary - virtAddr,
1213 kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
1214 flags);
1215 if (status != (kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
1216 VM_ERR("mmap failed, status: %d", status);
1217 return;
1218 }
1219 LOS_VmSpaceReserve(kSpace, kmallocLength, bssEndBoundary);
1220}
1221
1223{
1224 LosVmSpace *kSpace = LOS_GetKVmSpace();
1225 paddr_t oldTtPhyBase;
1226
1227 kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;
1228 kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
1229
1230 /* we need free tmp ttbase */
1231 oldTtPhyBase = OsArmReadTtbr0();//读取TTB值
1232 oldTtPhyBase = oldTtPhyBase & MMU_DESCRIPTOR_L2_SMALL_FRAME;
1233 OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);//内核页表基地址写入CP15 c2(TTB寄存器)
1234 ISB;
1235
1236 /* we changed page table entry, so we need to clean TLB here */
1237 OsCleanTLB();//清空TLB缓冲区
1238
1239 (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)(UINTPTR)(oldTtPhyBase - SYS_MEM_BASE + KERNEL_VMM_BASE));//释放内存池
1240}
1241
1242/* disable TTBCR0 and set the split between TTBR0 and TTBR1 */
1244{
1245 UINT32 n = __builtin_clz(KERNEL_ASPACE_BASE) + 1;
1246 UINT32 ttbcr = MMU_DESCRIPTOR_TTBCR_PD0 | n;
1247
1248 OsArmWriteTtbr1(OsArmReadTtbr0());//读取地址转换表基地址
1249 ISB;//指令同步隔离。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
1250 OsArmWriteTtbcr(ttbcr);
1251 ISB;
1252 OsArmWriteTtbr0(0);
1253 ISB;
1254}
1255
1256/*!
1257 * @brief OsInitMappingStartUp 开始初始化mmu
1258 *
1259 * @return
1260 *
1261 * @see
1262 */
1264{
1265 OsArmInvalidateTlbBarrier();//使TLB失效
1266
1267 OsSwitchTmpTTB();//切换到临时TTB ,请想想为何要切换到临时 @note_thinking
1268
1269 OsSetKSectionAttr(KERNEL_VMM_BASE, FALSE);//设置内核空间属性
1270 OsSetKSectionAttr(UNCACHED_VMM_BASE, TRUE);//设置未缓存空间属性
1272}
1273#endif
1274
1275
STATIC INLINE UINT32 OsArmReadTtbr0(VOID)
Definition: arm.h:91
STATIC INLINE VOID OsArmWriteTtbcr(UINT32 val)
Definition: arm.h:124
STATIC INLINE VOID OsArmWriteTlbiasidis(UINT32 val)
记录由协处理器记录当前是哪个进程在跑
Definition: arm.h:514
STATIC INLINE VOID OsArmWriteContextidr(UINT32 val)
Definition: arm.h:228
STATIC INLINE UINT32 OsArmReadTtbcr(VOID)
Definition: arm.h:117
STATIC INLINE VOID OsArmWriteTtbr1(UINT32 val)
Definition: arm.h:111
STATIC INLINE VOID OsArmWriteTtbr0(UINT32 val)
Definition: arm.h:98
NORETURN VOID LOS_Panic(const CHAR *fmt,...)
Kernel panic function.
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListDelete(LOS_DL_LIST *node)
Definition: los_list.h:292
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListAdd(LOS_DL_LIST *list, LOS_DL_LIST *node)
Insert a new node to a doubly linked list.
Definition: los_list.h:217
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
VOID * LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
从指定内存池中申请size长度的内存且地址按boundary字节对齐的内存
Definition: los_memory.c:1150
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
UINT8 * m_aucSysMem0
异常交互动态内存池地址的起始地址,当不支持异常交互特性时,m_aucSysMem0等于m_aucSysMem1。
Definition: los_memory.c:107
STATIC INT32 OsMapParamCheck(UINT32 flags, VADDR_T vaddr, PADDR_T paddr)
Definition: los_arch_mmu.c:204
STATIC INLINE VOID OsUnlockPte1Tmp(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:156
STATIC VOID OsCvtSecAttsToFlags(PTE_T l1Entry, UINT32 *flags)
Definition: los_arch_mmu.c:437
VOID LOS_ArchMmuContextSwitch(LosArchMmu *archMmu)
LOS_ArchMmuContextSwitch 切换MMU上下文
STATIC UINT32 OsCvtPte2CacheFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:726
STATIC UINT32 OsMapL2PageContinous(MmuMapInfo *mmuMapInfo, PTE_T *pte1, UINT32 *count)
Definition: los_arch_mmu.c:851
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_ArchMmuDestroy(LosArchMmu *archMmu)
LOS_ArchMmuDestroy 销毁MMU 和 initMmu 相呼应,释放页表页
STATIC VOID OsTryUnmapL1PTE(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t vaddr, UINT32 scanIndex, UINT32 scanCount)
Definition: los_arch_mmu.c:292
__attribute__((aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS)))
Definition: los_arch_mmu.c:98
STATIC UINT32 OsCvtSecFlagsToAttrs(UINT32 flags)
Definition: los_arch_mmu.c:409
STATIC STATUS_T OsGetL2Table(LosArchMmu *archMmu, UINT32 l1Index, paddr_t *ppa)
获取L2页表,分配L2表(需物理内存)
Definition: los_arch_mmu.c:686
VADDR_T * OsGFirstTableGet(VOID)
Definition: los_arch_mmu.c:186
STATUS_T LOS_ArchMmuChangeProt(LosArchMmu *archMmu, VADDR_T vaddr, size_t count, UINT32 flags)
LOS_ArchMmuChangeProt 修改进程空间虚拟地址区间的映射属性 改变内存段的访问权限,例如: 读/写/可执行/不可用 ==
Definition: los_arch_mmu.c:949
STATIC VOID OsSetKSectionAttr(UINTPTR virtAddr, BOOL uncached)
设置内核空间段属性,可看出内核空间是固定映射到物理地址
STATUS_T LOS_ArchMmuMove(LosArchMmu *archMmu, VADDR_T oldVaddr, VADDR_T newVaddr, size_t count, UINT32 flags)
LOS_ArchMmuMove 将进程空间一个虚拟地址区间的映射关系转移至另一块未使用的虚拟地址区间重新做映射。
Definition: los_arch_mmu.c:996
STATIC VOID OsPutL2Table(const LosArchMmu *archMmu, UINT32 l1Index, paddr_t l2Paddr)
Definition: los_arch_mmu.c:266
STATIC INLINE VOID OsUnlockPte2(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:175
BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb)
Definition: los_arch_mmu.c:537
STATIC UINT32 OsMapSection(MmuMapInfo *mmuMapInfo, UINT32 *count)
OsMapSection section页表格式项映射
Definition: los_arch_mmu.c:666
STATIC UINT32 OsMapL1PTE(MmuMapInfo *mmuMapInfo, PTE_T *l1Entry, UINT32 *count)
Definition: los_arch_mmu.c:806
STATIC UINT32 OsUnmapSection(LosArchMmu *archMmu, PTE_T *l1Entry, vaddr_t *vaddr, UINT32 *count)
Definition: los_arch_mmu.c:515
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
VOID OsArchMmuInitPerCPU(VOID)
STATIC UINT32 OsCvtPte2FlagsToAttrs(UINT32 flags)
Definition: los_arch_mmu.c:782
STATIC INLINE VOID OsUnlockPte1(SPIN_LOCK_S *lock, UINT32 intSave)
Definition: los_arch_mmu.c:135
STATIC UINT32 OsCvtSecAccessFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:379
STATIC SPIN_LOCK_S * OsGetPte1Lock(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
Definition: los_arch_mmu.c:130
VOID OsInitMappingStartUp(VOID)
OsInitMappingStartUp 开始初始化mmu
STATIC VOID OsKSectionNewAttrEnable(VOID)
STATIC UINT32 OsCvtSecCacheFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:353
STATIC UINT32 OsCvtPte2AccessFlagsToMMUFlags(UINT32 flags)
Definition: los_arch_mmu.c:752
STATIC INLINE PTE_T * OsGetPte2BasePtr(PTE_T pte1)
获取页表基地址
Definition: los_arch_mmu.c:180
STATIC INLINE SPIN_LOCK_S * OsGetPte2Lock(LosArchMmu *archMmu, PTE_T pte1, UINT32 *intSave)
Definition: los_arch_mmu.c:169
STATIC INLINE UINT32 OsUnmapL1Invalid(vaddr_t *vaddr, UINT32 *count)
解除L1表的映射关系
Definition: los_arch_mmu.c:192
STATIC SPIN_LOCK_S * OsGetPte1LockTmp(LosArchMmu *archMmu, PADDR_T paddr, UINT32 *intSave)
Definition: los_arch_mmu.c:143
STATIC UINT32 OsUnmapL2PTE(LosArchMmu *archMmu, PTE_T *pte1, vaddr_t vaddr, UINT32 *count)
Definition: los_arch_mmu.c:482
STATIC VOID OsSwitchTmpTTB(VOID)
切换临时页表
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
Definition: los_arch_mmu.c:569
STATIC VOID OsCvtPte2AttsToFlags(PTE_T l1Entry, PTE_T l2Entry, UINT32 *flags)
Definition: los_arch_mmu.c:221
https://blog.csdn.net/qq_38410730/article/details/81036768
STATUS_T OsAllocAsid(UINT32 *asid)
Definition: los_asid.c:78
VOID OsFreeAsid(UINT32 asid)
释放 asid
Definition: los_asid.c:96
CHAR __text_end
代码区结束地址
CHAR __rodata_end
ROM结束地址
CHAR __ram_data_start
RAM开始地址 可读可写
CHAR __bss_end
bss结束地址 attribute((section(".__bss_end")));
CHAR __text_start
代码区开始地址
CHAR __rodata_start
ROM开始地址 只读
STATIC INLINE PTE_T OsGetPte1(PTE_T *pte1BasePtr, vaddr_t va)
Definition: los_pte_ops.h:82
STATIC INLINE VOID OsSavePte1(PTE_T *pte1Ptr, PTE_T pte1)
PTE(Page Table Entry),页表条目,保存L1页表项至L1页表
Definition: los_pte_ops.h:50
STATIC INLINE BOOL OsIsPte1PageTable(PTE_T pte1)
Definition: los_pte_ops.h:87
STATIC INLINE PTE_T OsGetPte2(PTE_T *pte2BasePtr, vaddr_t va)
Definition: los_pte_ops.h:112
STATIC INLINE BOOL OsIsPte2SmallPageXN(PTE_T pte2)
Definition: los_pte_ops.h:160
STATIC INLINE BOOL OsIsPte2LargePage(PTE_T pte2)
Definition: los_pte_ops.h:165
STATIC INLINE UINT32 OsSavePte2Continuous(PTE_T *pte2BasePtr, UINT32 index, PTE_T pte2, UINT32 count)
Definition: los_pte_ops.h:124
STATIC INLINE PTE_T * OsGetPte1Ptr(PTE_T *pte1BasePtr, vaddr_t va)
pte1BasePtr L1 转换页表基地址
Definition: los_pte_ops.h:77
STATIC INLINE BOOL OsIsPte2SmallPage(PTE_T pte2)
Definition: los_pte_ops.h:155
STATIC INLINE BOOL OsIsPte1Section(PTE_T pte1)
Definition: los_pte_ops.h:97
STATIC INLINE UINT32 OsGetPte2Index(vaddr_t va)
Definition: los_pte_ops.h:102
STATIC INLINE PADDR_T OsGetPte1Paddr(PADDR_T PhysTtb, vaddr_t va)
Definition: los_pte_ops.h:72
STATIC INLINE BOOL OsIsPte1Invalid(PTE_T pte1)
Definition: los_pte_ops.h:92
STATIC INLINE VOID OsClearPte1(PTE_T *pte1Ptr)
Definition: los_pte_ops.h:67
STATIC INLINE UINT32 OsGetPte1Index(vaddr_t va)
获取L1 页表项索引
Definition: los_pte_ops.h:62
STATIC INLINE VOID OsClearPte2Continuous(PTE_T *pte2Ptr, UINT32 count)
Definition: los_pte_ops.h:143
STATIC INLINE ADDR_T OsTruncPte1(ADDR_T addr)
生成 L1 section格式项地址
Definition: los_pte_ops.h:57
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
VOID LOS_SpinInit(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:37
STATIC INLINE VOID OsArmInvalidateTlbBarrier(VOID)
Definition: los_tlb_v6.h:48
STATIC INLINE VOID OsCleanTLB(VOID)
Definition: los_tlb_v6.h:79
STATIC INLINE VOID OsArmInvalidateTlbMvaNoBarrier(VADDR_T va)
Definition: los_tlb_v6.h:59
STATIC INLINE VOID OsArmInvalidateTlbMvaRangeNoBarrier(VADDR_T start, UINT32 count)
Definition: los_tlb_v6.h:68
unsigned long PADDR_T
Definition: los_typedef.h:207
signed int INT32
Definition: los_typedef.h:60
int status_t
Definition: los_typedef.h:205
unsigned long paddr_t
Definition: los_typedef.h:209
unsigned long vaddr_t
Definition: los_typedef.h:206
unsigned long VADDR_T
Definition: los_typedef.h:208
unsigned long PTE_T
Definition: los_typedef.h:213
unsigned char UINT8
Definition: los_typedef.h:55
int STATUS_T
Definition: los_typedef.h:215
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
size_t BOOL
Definition: los_typedef.h:88
PADDR_T LOS_PaddrQuery(VOID *vaddr)
通过虚拟地址查询映射的物理地址
Definition: los_vm_map.c:550
LosVmSpace * LOS_GetKVmSpace(VOID)
内核空间只有g_kVmSpace一个,所有的内核进程都共用一个内核空间
Definition: los_vm_map.c:130
STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr)
LosVmPage * LOS_VmPageGet(PADDR_T paddr)
通过物理地址获取页框
Definition: los_vm_page.c:120
LosVmPage * OsVmPaddrToPage(paddr_t paddr)
Definition: los_vm_phys.c:267
VOID LOS_PhysPageFree(LosVmPage *page)
释放一个物理页框
Definition: los_vm_phys.c:546
PADDR_T OsKVaddrToPaddr(VADDR_T kvaddr)
Definition: los_vm_phys.c:519
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
内存管理单元(英语:memory management unit,缩写为MMU),有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。
Definition: los_arch_mmu.h:86
SPIN_LOCK_S lock
Definition: los_arch_mmu.h:88
VADDR_T * virtTtb
Definition: los_arch_mmu.h:90
UINT32 asid
Definition: los_arch_mmu.h:92
PADDR_T physTtb
Definition: los_arch_mmu.h:91
LOS_DL_LIST ptList
Definition: los_arch_mmu.h:93
VADDR_T virt
虚拟地址
Definition: los_vm_boot.h:54
unsigned int flags
标识 读/写/.. VM_MAP_REGION_FLAG_PERM_*
Definition: los_vm_boot.h:56
PADDR_T phys
物理地址
Definition: los_vm_boot.h:53
size_t size
大小
Definition: los_vm_boot.h:55
LosArchMmu * archMmu
Definition: los_arch_mmu.c:90
VADDR_T * vaddr
Definition: los_arch_mmu.c:91
UINT32 * flags
Definition: los_arch_mmu.c:93
PADDR_T * paddr
Definition: los_arch_mmu.c:92
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
SPIN_LOCK_S lock
Definition: los_vm_page.h:63
LOS_DL_LIST node
Definition: los_vm_page.h:54
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosArchMmu archMmu
Definition: los_vm_map.h:157