一、前言

某天,wowo同学突然来了一句:如果要在start_kernel中点LED,ioremap在什么时间点才能调用呢?我想他应该是想通过点LED灯来调试start_kernel之后的初始化的代码(例如DTB解析部分的代码)。那天,我们两个花了二十分钟的时间,讨论相关的问题,我觉得很有意思,因此决定写fix mapped address这样的一份文档。

在汇编代码中,由于没有打开MMU,想怎么访问外设都很简单,直接使用物理地址即可,然而,进入start kernel之后(打开了MMU),想要访问硬件都是那么的不方便,至少需要通过ioremap获取了虚拟地址之后才可以访问。但是,实际上,在内核的启动的初始阶段,内存管理子系统还没有ready,ioremap还不能调用(在mm_init之后可以正常使用)。

实际上,这个需求是和early ioremap模块相关,此外,还有一些其他的需求,内核合并了这些需求并提出了fix mapped address的概念。本文就是描述关于fix mapped address的方方面面,BTW,本文的代码来自4.4.6内核,体系结构相关的代码依然选择的是ARM64。

二、什么是fixmap?

Fix map中的fix指的是固定的意思,那么固定什么东西呢?其实就是虚拟地址是固定的,也就是说,有些虚拟地址在编译(compile-time)的时候就固定下来了,而这些虚拟地址对应的物理地址不是固定的,是在kernel启动过程中被确定的。为了方便大家理解fixmap,我们提供一个具体的例子:DTB image的处理。

实际上DTB的处理一开始并没有使用fixmap,而是放在了kernel image附近。更具体的要求是必须放在kernel image起始地址的512M内,8字节对齐,dtb image不能越过2M section size的边界。之所以这么要求,主要是想借用kernel image页表的“东风”,反正建立kernel image所需要的PGD/PUD/PMD页表都已经静态分配了,对dtb image的要求可以不需要建立新的页表,只是在原有的页表中增加一个entry而已,不过这样的设计存在下面的问题:

(1)对dtb image的位置有限制,不是很灵活(谁不想自由自在呢?bootload copy dtb img的时候当然想了无牵挂啊)。

(2)对dtb image的位置检查在head.S中,需要汇编实现(谁想写汇编啊,用c实现多买易懂啊,可维护性,可移植性多么好啊)。

现在,既然内核有了early fixmap的支持,那么上面的限制都可以放宽了。整个dtb image的处理过程如下:

(1)bootloader copy dtb image到memory的某个位置上。具体的位置随便,当然还是要满足8字节对齐,dtb image不能越过2M section size的边界的要求,毕竟我们也想一条section mapping就搞定dtb image。

(2)bootload通过寄存器x0传递dtb image的物理地址,dtb image的虚拟地址在编译kernel image的时候就确定了。

(3)汇编初始化阶段不对dtb image做任何处理

(4)在start kernel之后的初始化代码中(具体在setup_arch--->setup_machine_fdt中),创建dtb image的相关Translation tables,之后就可以自由的访问dtb image了。

三、为何有fixmap这个概念?

动态分配虚拟地址以及建立地址映射是一个复杂的过程,在内核完全启动之后,内存管理可以提供各种丰富的API让内核的其他模块可以完成虚拟地址分配和建立地址映射的功能,但是,在内核的启动过程中,有些模块需要使用虚拟内存并mapping到指定的物理地址上,而且,这些模块也没有办法等待完整的内存管理模块初始化之后再进行地址映射。因此,linux kernel固定分配了一些fixmap的虚拟地址,这些地址有固定的用途,使用该地址的模块在初始化的时候,讲这些固定分配的地址mapping到指定的物理地址上去。

最直观的需求来自初始化代码的调试,想一想当我们来到start_kernel的时候我们面临的处境:

(1)我们不能访问全部的内存,只能访问kernel image附近的memory。

(2)我们不能访问任何的硬件,所有的io memory还没有mapping

想要通过串口控制台输出错误信息?sorry,现在离console驱动的初始化还早着呢。想点个LED灯看看内核运行情况?sorry,ioremp函数需要kmalloc分配内存,但是伙伴系统还没有初始化呢。怎么办?一个最简洁的方法就是简化虚拟内存的分配和管理(ioremp中使用的管理虚拟内存地址的方法太重了),而最简单的方法就是fix virtual address。

四、fixmap的具体位置在那里?

fixmap的地址区域位于FIXADDR_START和FIXADDR_TOP之间,具体可以参考下图:

上图中,红色框的block就是fixmap address的具体位置。

五、fixmap具体应用在哪些场景?

fixmap的地址区域有被进一步细分,如下:

enum fixed_addresses {
    FIX_HOLE, 
    FIX_FDT_END,
    FIX_FDT = FIX_FDT_END + FIX_FDT_SIZE / PAGE_SIZE - 1,

FIX_EARLYCON_MEM_BASE,
    FIX_TEXT_POKE0,
    __end_of_permanent_fixed_addresses,

FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
    FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
    __end_of_fixed_addresses
};

由定义可知,fixmap地址区域又分成了两个部分,一部分叫做permanent fixed address,是用于具体的某个内核模块的,使用关系是永久性的。另外一个叫做temporary fixed address,各个内核模块都可以使用,用完之后就释放,模块和虚拟地址之间是动态的关系。

permanent fixed address主要涉及的模块包括:

(1)dtb解析模块。

(2)early console模块。标准的串口控制台驱动的初始化在整个kernel初始化过程中是很靠后的事情了,如果能够在kernel启动阶段的初期就有一个console,能够输出各种debug信息是多买美妙的事情啊,early console就能满足你的这个愿望,这个模块是使用early param来初始化该模块的功能的,因此可以很早就投入使用,从而协助工程师了解内核的启动过程。

(3)动态打补丁的模块。正文段一般都被映射成read only的,该模块可以使用fix mapped address来映射RW的正文段,从动态修改程序正文段,从而完成动态打补丁的功能。

temporary fixed address主要用于early ioremap模块。linux kernel在fix map区域的虚拟地址空间中开了FIX_BTMAPS_SLOTS个的slot(每个slot的size是NR_FIX_BTMAPS),内核中的模块都能够通过early_ioremap、early_iounmap的接口来申请或者释放对某个slot 虚拟地址的使用。

Fix-Mapped Addresses的更多相关文章

  1. 保留ip: Reserved IP addresses

    Reserved IP addresses From Wikipedia, the free encyclopedia     In the Internet addressing architect ...

  2. 《Peering Inside the PE: A Tour of the Win32 Portable Executable File Format》阅读笔记二

    Common Sections The .text section is where all general-purpose code emitted by the compiler or assem ...

  3. PE Header and Export Table for Delphi

    Malware Analysis Tutorial 8: PE Header and Export Table 2. Background Information of PE HeaderAny bi ...

  4. 【转】Django Model field reference学习总结

    Django Model field reference学习总结(一) 本文档包含所有字段选项(field options)的内部细节和Django已经提供的field types. Field 选项 ...

  5. 《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)

    通常说函数返回某个错误值,实际上是函数返回值为-1,而全局变量errno被置为指定的常值(即称函数返回这个错误值). exit终止进程,Unix在一个进程终止时总是关闭该进程所有打开的描述符. TCP ...

  6. Network Object NAT配置介绍

    1.Dynamic NAT(动态NAT,动态一对一) 实例一: 传统配置方法: nat (Inside) 1 10.1.1.0 255.255.255.0 global (Outside) 1 202 ...

  7. Django Model field reference

    ===================== Model field reference ===================== .. module:: django.db.models.field ...

  8. devm_xxx机制【转】

    前言 devm是内核提供的基础机制,用于方便驱动开发者所分配资源的自动回收.参考内核文档devres.txt.总的来说,就是驱动开发者只需要调用这类接口分配期望的资源,不用关心释放问题.这些资源的释放 ...

  9. POSIX-Data Structure

    struct sigevent The <signal.h> header shall define the sigeventstructure, which shall include ...

随机推荐

  1. 深入理解VUE样式style层次分析

    刚开始使用vue的时候容易被里面的样式搞懵: 样式可以在main.js中引入,在模块js文件中引入,在组件中的style标签引入,在组件中的script标签引入,还可以在index.html的body ...

  2. linux用户管理中两个重要的“父子”配置文件

    在Linux中主要通过用户配置文件来查看和修改用户信息,因此下面我们将介绍两个重要的用户配置文件,让你能够更好的hold住你的用户. 一:父文件/etc/passwd 1.查看配置文件/etc/pas ...

  3. Win10系统下软件UI显示不完整解决方案

    在最初升级win10的时候就想到了这些问题,例如和各种软件的不兼容性.当然,事实上win10并没有想象的那么糟,作为一个windows user 来说,win10的确是很高大上的,无论是颜值或者是体验 ...

  4. C++中用完需要释放掉内存的几个类

      BSTR BSTR bstrXML = NULL; //用完以后,或者 catch段中 if(bstrXML) ::SysFreeString(result); VARIANT VARIANT v ...

  5. [Backbone]2. More detail in Models

    Our Appointment model doesn't seem too useful yet. Add two default attributes, title as the string & ...

  6. activemq无法启动且后台管理界面进不去的解决办法

    从官网下载了一个最新的activemq,目前最新版本是5.14.5 我下载的是windows版本,通过执行%activemq home%/bin/win64/InstallService.bat,可以 ...

  7. (C++)UrlEncode的标准实现

    http://blog.163.com/xiaopengyan_109/blog/static/149832173201072685539394/ 地址栏传中文参数后是什么编码格式 网页中的表单使用P ...

  8. ASP.NET之旅--深入浅出解读IIS架构

    在学习Asp.net时,发现大多数作者都是站在一个比较高的层次上讲解Asp.Net. 他们耐心. 细致地告诉你如何一步步拖放控件. 设置控件属性.编写 CodeBehind代码,以实现某个特定的功能. ...

  9. 微信小程序 - 自定义tabbar

    更新: 2019-1-18:自定义tabbar组件已发布 各种奇葩的需求,造就了我们 wxml <view class="nav-tabs"> <view cla ...

  10. URAL 题目1297. Palindrome(后缀数组+RMQ求最长回文子串)

    1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just ...