鸿蒙轻内核A核源码分析系列五 虚实映射(2)虚实映射初始化

2、 虚拟映射初始化

在文件kernel/base/vm/los_vm_boot.c中的系统内存初始化函数OsSysMemInit()会调用虚实映射初始化函数OsInitMappingStartUp()。该函数代码定义在文件arch/arm/arm/src/los_arch_mmu.c,代码如下。⑴处函数使TLB失效,清理虚实映射缓存数据,涉及些cp15寄存器和汇编,后续再分析。⑵处函数切换到临时TTB。⑶处设置内核地址空间的映射。下面分别详细这些函数代码。

VOID OsInitMappingStartUp(VOID)
{
⑴   OsArmInvalidateTlbBarrier();

⑵   OsSwitchTmpTTB();

⑶  OsSetKSectionAttr(KERNEL_VMM_BASE, FALSE);
    OsSetKSectionAttr(UNCACHED_VMM_BASE, TRUE);
    OsKSectionNewAttrEnable();
}

2.1 函数OsSwitchTmpTTB

函数OsSwitchTmpTTB申请16KiB的内存存放L1页表项数据,把页表项数据从g_firstPageTable复制到申请的内存区域。⑴处获取内核地址空间。L1页表由4096个页表项组成,每个4 bytes,共需要16KiB大小。所以⑵处代码按16KiB对齐申请16KiB大小的内存区域存放L1页表项。⑶处设置内核虚拟内存地址空间的转换表基地址TTB。⑷处把g_firstPageTable页表数据复制到内核地址空间的转换表区域。如果复制失败,则直接使用g_firstPageTable。⑸处设置内核虚拟地址空间的TTB转换地址对应的物理内存地址,然后调用函数OsArmWriteTtbr0写入MMU寄存器。

STATIC VOID OsSwitchTmpTTB(VOID)
{
    PTE_T *tmpTtbase = NULL;
    errno_t err;
⑴   LosVmSpace *kSpace = LOS_GetKVmSpace();

    /* ttbr address should be 16KByte align */
⑵   tmpTtbase = LOS_MemAllocAlign(m_aucSysMem0, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
                                  MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);
    if (tmpTtbase == NULL) {
        VM_ERR("memory alloc failed");
        return;
    }

⑶  kSpace->archMmu.virtTtb = tmpTtbase;
⑷  err = memcpy_s(kSpace->archMmu.virtTtb, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS,
                   g_firstPageTable, MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS);
    if (err != EOK) {
        (VOID)LOS_MemFree(m_aucSysMem0, tmpTtbase);
        kSpace->archMmu.virtTtb = (VADDR_T *)g_firstPageTable;
        VM_ERR("memcpy failed, errno: %d", err);
        return;
    }
⑸  kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
    OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);
    ISB;
}

2.2 函数OsSetKSectionAttr

内部函数OsSetKSectionAttr用于设置内核虚拟地址空间的区间属性,分别针对内核虚拟地址空间的内核区间[KERNEL_ASPACE_BASE,KERNEL_ASPACE_BASE+KERNEL_ASPACE_SIZE]和未缓存区间[UNCACHED_VMM_BASE,UNCACHED_VMM_BASE+UNCACHED_VMM_SIZE]进行设置。内核虚拟地址空间是固定映射到物理内存的,内核地址空间的映射包含代码段、数据段、堆栈区间映射,如下示意图所示:

⑴处计算相对内核虚拟地址空间基地址KERNEL_VMM_BASE的偏移大小。⑵处先计算相对偏移值的text、rodata、data_bss段的虚拟内存地址,然后创建这些段的虚实映射关系数组mmuKernelMappings。⑶处设置内核虚拟地址区间的虚拟转换基地址TTB和物理转换基地址TTB。然后解除虚拟地址virtAddr的虚实映射,解除映射的长度就是代码段、只读数据段、数据BSS段这些内存段的长度。⑷处按指定的标签flags对text代码段之前的内存区间进行虚实映射。⑸处映射text代码段、rodata只读数据段、data_bss数据段的内存区间,并调用函数LOS_VmSpaceReserve在进程空间中预定地址区间。⑹是BSS段后面的heap区、stack区的映射,映射虚拟地址空间的内存堆栈区间到对应的物理内存区间。

STATIC VOID OsSetKSectionAttr(UINTPTR virtAddr, BOOL uncached)
{
⑴  UINT32 offset = virtAddr - KERNEL_VMM_BASE;
    /* every section should be page aligned */
⑵  UINTPTR textStart = (UINTPTR)&__text_start + offset;
    UINTPTR textEnd = (UINTPTR)&__text_end + offset;
    UINTPTR rodataStart = (UINTPTR)&__rodata_start + offset;
    UINTPTR rodataEnd = (UINTPTR)&__rodata_end + offset;
    UINTPTR ramDataStart = (UINTPTR)&__ram_data_start + offset;
    UINTPTR bssEnd = (UINTPTR)&__bss_end + offset;
    UINT32 bssEndBoundary = ROUNDUP(bssEnd, MB);
    LosArchMmuInitMapping mmuKernelMappings[] = {
        {
            .phys = SYS_MEM_BASE + textStart - virtAddr,
            .virt = textStart,
            .size = ROUNDUP(textEnd - textStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
            .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE,
            .name = "kernel_text"
        },
        {
            .phys = SYS_MEM_BASE + rodataStart - virtAddr,
            .virt = rodataStart,
            .size = ROUNDUP(rodataEnd - rodataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
            .flags = VM_MAP_REGION_FLAG_PERM_READ,
            .name = "kernel_rodata"
        },
        {
            .phys = SYS_MEM_BASE + ramDataStart - virtAddr,
            .virt = ramDataStart,
            .size = ROUNDUP(bssEndBoundary - ramDataStart, MMU_DESCRIPTOR_L2_SMALL_SIZE),
            .flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE,
            .name = "kernel_data_bss"
        }
    };
    LosVmSpace *kSpace = LOS_GetKVmSpace();
    status_t status;
    UINT32 length;
    int i;
    LosArchMmuInitMapping *kernelMap = NULL;
    UINT32 kmallocLength;
    UINT32 flags;

    /* use second-level mapping of default READ and WRITE */
⑶  kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;
    kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);
    status = LOS_ArchMmuUnmap(&kSpace->archMmu, virtAddr,
                              (bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT);
    if (status != ((bssEndBoundary - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
        VM_ERR("unmap failed, status: %d", status);
        return;
    }

    flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE | VM_MAP_REGION_FLAG_PERM_EXECUTE;
    if (uncached) {
        flags |= VM_MAP_REGION_FLAG_UNCACHED;
    }
⑷  status = LOS_ArchMmuMap(&kSpace->archMmu, virtAddr, SYS_MEM_BASE,
                            (textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
                            flags);
    if (status != ((textStart - virtAddr) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
        VM_ERR("mmap failed, status: %d", status);
        return;
    }

⑸  length = sizeof(mmuKernelMappings) / sizeof(LosArchMmuInitMapping);
    for (i = 0; i < length; i++) {
        kernelMap = &mmuKernelMappings[i];
        if (uncached) {
            kernelMap->flags |= VM_MAP_REGION_FLAG_UNCACHED;
        }
        status = LOS_ArchMmuMap(&kSpace->archMmu, kernelMap->virt, kernelMap->phys,
                                 kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT, kernelMap->flags);
        if (status != (kernelMap->size >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
            VM_ERR("mmap failed, status: %d", status);
            return;
        }
        LOS_VmSpaceReserve(kSpace, kernelMap->size, kernelMap->virt);
    }

⑹   kmallocLength = virtAddr + SYS_MEM_SIZE_DEFAULT - bssEndBoundary;
    flags = VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE;
    if (uncached) {
        flags |= VM_MAP_REGION_FLAG_UNCACHED;
    }
    status = LOS_ArchMmuMap(&kSpace->archMmu, bssEndBoundary,
                            SYS_MEM_BASE + bssEndBoundary - virtAddr,
                            kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT,
                            flags);
    if (status != (kmallocLength >> MMU_DESCRIPTOR_L2_SMALL_SHIFT)) {
        VM_ERR("mmap failed, status: %d", status);
        return;
    }
    LOS_VmSpaceReserve(kSpace, kmallocLength, bssEndBoundary);
}

2.3 函数OsKSectionNewAttrEnable

函数OsKSectionNewAttrEnable设置虚实地址的转换表基地址TTB并清楚TLB缓存。⑴处获取内核虚拟进程空间,⑵处设置进程空间MMU的虚拟地址转换表基地址TTB,然后查询到物理内存地址并设置物理内存地址转换表基地址。⑶处从CP15 C2寄存器读取TTB地址,取高20位。⑷处将内核物理内存页表基地址写入CP15 c2 TTB寄存器。⑸处清空TLB缓冲区,然后释放内存。涉及到了MMU寄存器,后续系列会专门详细讲解。

STATIC VOID OsKSectionNewAttrEnable(VOID)
{
⑴  LosVmSpace *kSpace = LOS_GetKVmSpace();
    paddr_t oldTtPhyBase;

⑵  kSpace->archMmu.virtTtb = (PTE_T *)g_firstPageTable;
    kSpace->archMmu.physTtb = LOS_PaddrQuery(kSpace->archMmu.virtTtb);

    /* we need free tmp ttbase */
⑶  oldTtPhyBase = OsArmReadTtbr0();
    oldTtPhyBase = oldTtPhyBase & MMU_DESCRIPTOR_L2_SMALL_FRAME;
⑷  OsArmWriteTtbr0(kSpace->archMmu.physTtb | MMU_TTBRx_FLAGS);
    ISB;

    /* we changed page table entry, so we need to clean TLB here */
⑸  OsCleanTLB();

    (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)(UINTPTR)(oldTtPhyBase - SYS_MEM_BASE + KERNEL_VMM_BASE));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/704169.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32的简易智能家居设计(嘉立创支持)

一、项目功能概述 1、OLED显示温湿度、空气质量&#xff0c;并可以设置报警阈值 2、设置4个继电器开关&#xff0c;分别控制灯、空调、开关、风扇 3、设计一个离线语音识别系统&#xff0c;可以语音控制打开指定开关、并且可以显示识别命令词到OLED屏上 4、OLED实时显示&#…

在k8s中部署Elasticsearch高可用集群详细教程

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《洞察之眼&#xff1a;ELK监控与可视化》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Elasticsearch简介 2、为什么在k8s中部署elasti…

计算机毕业三年的我,辞职两次后找不到工作回家,此时是真的羡慕有手艺在手的人

栀子花香&#xff0c;弥漫在空气中&#xff0c;却掩盖不了内心的苦涩。 半年&#xff0c;两份工作&#xff0c;两次裸辞&#xff0c;我&#xff0c;又成了一个身无分文的“废人”。 曾经&#xff0c;我也是人人羡慕的互联网人&#xff0c;月薪6K&#xff0c;过着“955”的“神…

LeetCode | 27.移除元素

这道题的思路和26题一模一样&#xff0c;由于要在元素组中修改&#xff0c;我们可以设置一个index表示目前要修改原数组的第几位&#xff0c;由于遍历&#xff0c;访问原数组永远会在我们修改数组之前&#xff0c;所以不用担心数据丢失的问题&#xff0c;一次遍历数组&#xff…

别再忽视数组排序的重要性了

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

JavaSE---类和对象(上)

1. 面向对象的初步认知 1.1 什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。用面向对象…

kettle从入门到精通 第六十八课 ETL之kettle kettle随机数生成的一些方案

1、在做ETL数据抽取的时候&#xff0c;会用到生成随机数的功能&#xff0c;今天我们一起来学习下如何生成随机数据。如下图所示 2、将生成随机数拉倒画布即可&#xff0c;然后设置字段名称和选择合适的类型&#xff0c;如下图所示&#xff1a; 类型&#xff1a; 随机数字&…

自动同步库数据——kettle开发36

kettle中的那些人工智能。 一、kettle的AI能力目录 跨库同步 2.自动开发 3.自动优化 二、AI实例 1、跨库同步 sqlsever表同步至oracle数据库 1.1源库sqlserver 1.2目标库oracle 1.3可视化跨库同步 使用多表复制向导 选择跨库的表&#xff0c;下一步下一步&#xff0c;即可…

企业的crm客户管理系统的部署方式,是选私有云部署,还是公有云部署?

随着&#xff0c;现代化企业的发展&#xff0c;企业在选型CRM客户管理系统后&#xff0c;通过会选一种部署方式&#xff0c;然后才将其与企业现有的管理系统对接&#xff0c;那么一般企业在部署CMR客户管理系统时&#xff0c;一般会选哪种部署方式呢&#xff1f;是私有云crm部署…

笨蛋学算法之LeetCodeHot100_4_移动零(Java)

package com.lsy.leetcodehot100;public class _Hot4_移动零 {public static int[] moveZeroes(int[] nums){//判断数组是否为nullif(numsnull && nums.length0){return null;}/*** 初始化两个指针 i 和 noZero&#xff0c;其中 i 用于遍历数组&#xff0c;noZero 用于…

系统思考与创新解决

刚刚完成了为期两天的《系统思考与创新解决》课程&#xff0c;专门面向前端销售管理者。在这两天里&#xff0c;我们深入讨论了众多与公司当前状况密切相关的议题。通过绘制系统环路图&#xff0c;我们一起探索了包括客户满意度、交付周期、市场份额、研发投入、产能利用率、营…

主流3D视频编码技术

3D视频通过模拟人眼的立体视觉&#xff0c;使我们能够感受到深度和距离&#xff0c;提供了一种更加真实而富有沉浸感的视觉体验。长期以来&#xff0c;大量3D视频内容并没有使用专用的视频编码标准&#xff0c;而是使用通用的视频编码标准进行编码。主要的做法是将3D视频以SBS&…

基于springboot高校就业招聘系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;就业咨询管理&#xff0c;毕业去向管理&#xff0c;简历管理&#xff0c;管理员管理&#xff0c;基础数据管理 辅导员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;就业咨询管理…

消息队列的应用场景有哪些

通常来说&#xff0c;使用消息队列主要能为我们的系统带来下面三点好处&#xff1a; 异步处理 削峰/限流 降低系统耦合性 除了这三点之外&#xff0c;消息队列还有其他的一些应用场景&#xff0c;例如实现分布式事务、顺序保证和数据流处理。 异步处理 通过异步处理提高系…

JetLinks开源物联网平台社区版部署教程

1.上github搜素jetlinks 2.找到源代码&#xff0c;并且下载到本地。 3.项目下载完成之后&#xff0c;还需要另外下载三个核心依赖模块。在github找到jetlinks。 4.点击进去下载&#xff0c;下载完成之后&#xff0c;你会发现里面有三个文件夹是空白的&#xff0c;先不用理会&am…

springboot 整合redis问题,缓存击穿,穿透,雪崩,分布式锁

boot整合redis 压力测试出现失败 解决方案 排除lettuce 使用jedis <!-- 引入redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclus…

Diffusers代码学习: 文本引导深度图像生成

StableDiffusionDepth2ImgPipeline允许传递文本提示和初始图像&#xff0c;以调节新图像的生成。此外&#xff0c;还可以传递depth_map以保留图像结构。如果没有提供depth_map&#xff0c;则管道通过集成的深度估计模型自动预测深度。 # 以下代码为程序运行进行设置 import o…

【C++题解】1469. 数的统计

问题&#xff1a;1469. 数的统计 类型&#xff1a;嵌套循环 题目描述&#xff1a; 试计算在区间 1 到 n 的所有整数中&#xff0c;数字 x ( 0≤x≤9 )共出现了多少次&#xff1f; 例如&#xff0c;在 1 到 11 中&#xff0c;即在 1,2,3,4,5,6,7,8,9,10,11 中&#xff0c;数字…

20.1 JSON-JSON接口以及在Go语言中使用JSON

1. 简介 JSON即JavaScript对象表示法(JavaScript Object Notation)&#xff0c;是一种用于存储和交换数据的格式&#xff0c;是一种可供人类阅读和理解的纯文本格式。 JSON既可以键值对的形式&#xff0c;也可以数组的形式&#xff0c;表示数据。 JSON最初是JavaScript的一个…

FPGA专项课程即将开课,颁发AMD官方证书

社区成立以来&#xff0c;一直致力于为广大工程师提供优质的技术培训和资源&#xff0c;得到了众多用户的喜爱与支持。为了满足用户需求&#xff0c;我们特别推出了“基于Vitis HLS的高层次综合及图像处理开发”课程。 本次课程旨在帮助企业工程师掌握前沿的FPGA技术&#xff…