一、前言

某天,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. SCSI contrller的几种类型的区别

    在VMware vSphere Web Client中, 可以为虚拟机添加一个新的SCSI controller, 选项中包含如下的类型, 那么他们有什么区别呢? 如何选择呢?   BusLogic ...

  2. 集合 数组 定义 转换 遍历 Arrays API MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. Bootstrap学习js插件篇之滚动监听

    1.滚动监听 案例 滚动监听插件可以根据滚动条的位置自动更新所对应的导航标记.Bootstrap中文网左侧就是一个滚动监听的例子. 代码段: <nav id="navbar-examp ...

  4. 20个令人惊叹的音乐应用程序UI,值得收藏

    我们无法想象世界上没有手机.他们已经成为日常生活中不可缺失的一部分.今天的手机可以让你不只是拨打电话和发送消息.它可以让你浏览网页空间,拍照,看书,听音乐等等. 回顾一下互联网,你会看到不同的音乐AP ...

  5. 让ie6(opera)支持微软雅黑字体

    一.让IE6支持微软雅黑,添加一句声明: <html  lang="zh-CN"> 在网页的HTML标签内加入红色部分的声明,就可以了. 二.让Opera浏览器支持微软 ...

  6. IOS之导航控制器传值

    UITableView有两种风格:UITableViewStylePlain和UITableViewStyleGrouped.这两者操作起来其实并没有本质区别,只是后者按分组样式显示前者按照普通样式显 ...

  7. win7取消任务栏预览并显示文件名

    开始--运行--regedit--回车,然后注册表就打开了,之后开始找到如下的位置,新增2个项 HKEY_CURRENT_USER\Software\Microsoft\Windows\Current ...

  8. 程序员们必备的10款免费jquery插件

    本周带来10款免费的jquery插件.如果你也有好的作品,欢迎分享到社区中来,在得到帮助的同时,也能与更多人分享来自你的作品. jQuery导航菜单置顶插件 - stickyUp . 在线演示 sti ...

  9. C#.NET常见问题(FAQ)-如何引用定义好的dll文件

    1 添加引用,找到dll文件   2 引用类的名称空间,生成类的实例,调用类的方法,测试OK.     更多教学视频和资料下载,欢迎关注以下信息: 我的优酷空间: http://i.youku.com ...

  10. ios8 xcode6 下的启动界面设置和图标设置

    IOS8 我试了网上不少设置启动动画的,不知道是不是我弄错了还是怎么的,反正启动不了,后来在code4论坛找到了这个: 启动屏幕:LaunchScreen.xib文件 桌面图标等相关app图片:Ima ...