我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的

物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系。

这句话瞬间让我惊呆了,根据我的CPU的知识,开启分页之后,任何寻址都要经过mmu的转换,也就是一个二级查表的过程(386)

难道内核很特殊,当mmu看到某个逻辑地址是内核传来的之后,就不查表了,直接减去0xC0000000,然后就传递给内存控制器了???

我发现网上也有人和我问了同样的问题,看这个问题

这句话太让人费解了,让人费解到以至于要怀疑人生了,难道我过去所有学习到的知识全是错的?

以至于我们就开始胡思乱想了,“那么内核寻址的时候是怎么处理的,是把分页关了,还是用其他的方法绕过去的。”

是啊,我们好聪明,聪明到开始怀疑,内核想要实现这个简单的相减关系是不是进内核就把分页关了,或者,有某些牛叉的,我们不知道的方法绕过分页机制??

不然TMD我们怎么理解这句话?

去看书吧,看看《深入理解linux内核》吧,翻到75页,看那么一段话:

“宏__pa用于把从PAGE_OFFSET开始的线性地址转换成相应的物理地址,而宏__va做相反的转换。”

#define __pa(x)   ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) 代码一旦出来,看来一切都不用争论了,毕竟代码说明一切啊,然而这是事实嘛?

http://bbs.csdn.net/topics/100049760 有这个问题的人也不少,以至于人们开始争论起来了。

看完这篇帖子之后,我的内心开始鉴定了一些东西。

误解,这里一定有一个很大的误解,这个很大的误解就来源于,把linux的内存寻址和linux的内存管理搞混了。

第一:内核寻址肯定是经过页表转换的,页全局目录在编译时候静态初始化,768项到1023项(这决定了线性地址的3g到4g的范围)被映射到了0到1g的地方。

任何3g-4g的地址空间的地址(先不考虑高端内存)经过页表转换后就是0-1g的地址空间。但是TMD的是这个关系,但是说的好像不要经过页表转换似得。

第二:内核的宏__pa和__va有什么用呢?用在哪里?

于是我盯着unsigned long phys_addr这个东西使劲看,使劲看,我看了大半夜忽然明白,这代码里到处都是。。。(哈哈)

phys_addr是个变量,是个unsigned long的变量,变量吗,都有地址,我们假设这个地址是0xC0004323,这个地址的内容是0x0000ff3e

0xC0004323: 0x0000ff3e

我们让eax = phys_addr了,于是eax等于0x0000ff3e了,可是我们想访问这个地址的值,怎么办啊?

只有先获得va,把eax+0xc000_0000,然后在进行内存访问,经过页表转换后,传递给内存控制器的地址正好是0x0000ff3e,我们也正好能访问这个地址的值。

而假如把0x0000ff3e交给mmu,经过页表转换后,我们就不知道是什么东西了。

想通了之后又两个感慨,一是,unsigned long phys_addr不是指针胜似指针啊。第二个感慨是原来va和pa的用途在这里。

在把“宏__pa用于把从PAGE_OFFSET开始的线性地址转换成相应的物理地址,而宏__va做相反的转换。”这句话评论成瞎扯淡之后,整章我理解通了。

我随便找了一个内核函数

/*
* Change the memory type for the physial address range in kernel identity
* mapping space if that range is a part of identity map.
*/
int kernel_map_sync_memtype(u64 base, unsigned long size, unsigned long flags)
{
unsigned long id_sz; if (base > __pa(high_memory-))
return ; /*
* some areas in the middle of the kernel identity range
* are not mapped, like the PCI space.
*/
if (!page_is_ram(base >> PAGE_SHIFT))
return ; id_sz = (__pa(high_memory-) <= base + size) ?
__pa(high_memory) - base :
size; if (ioremap_change_attr((unsigned long)__va(base), id_sz, flags) < ) {
printk(KERN_INFO "%s:%d ioremap_change_attr failed %s "
"for [mem %#010Lx-%#010Lx]\n",
current->comm, current->pid,
cattr_name(flags),
base, (unsigned long long)(base + size-));
return -EINVAL;
}
return ;
}

我们首先要明白,要想获得base的值和high_memory的值,肯定是经过页表转换,访问内存才能得到值啊。

然而这个值恰好是地址而已,对这个值,进行pa,va转换,然后访问内存,看到这里,懂了吧。

【读书笔记::深入理解linux内核】内存寻址的更多相关文章

  1. 【读书笔记::深入理解linux内核】内存寻址【转】

    转自:http://www.cnblogs.com/likeyiyy/p/3837272.html 我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0 ...

  2. 深入理解linux内核-内存寻址

    逻辑地址:由一个段和偏移量组成的地址线性地址(虚拟地址):物理地址:CPU的物理地址线相对应的地址32或36位 多处理器系统中每个CPU对应一个GDT 局部线程存储:用于线程内部的各个函数调用都能访问 ...

  3. 【读书笔记】《Linux内核设计与实现》进程管理与进程调度

    大学跟老师做嵌入式项目,写过I2C的设备驱动,但对Linux内核的了解也仅限于此.Android系统许多导致root的漏洞都是内核中的,研究起来很有趣,但看相关的分析文章总感觉隔着一层窗户纸,不能完全 ...

  4. 《Linux内核设计与实现》读书笔记 第一章 Linux内核简介

    一.相关历史 1. Unix内核的特点 简洁:仅提供系统调用并有一个非常明确的设计目的 抽象:几乎所有东西都被当做文件 可移植性:使用C语言编写,使得其在各种硬件体系架构面前都具备令人惊异的移植能力 ...

  5. 《深入理解Linux内核》 读书笔记

    深入理解Linux内核 读书笔记 一.概论 操作系统基本概念 多用户系统 允许多个用户登录系统,不同用户之间的有私有的空间 用户和组 每个用于属于一个组,组的权限和其他人的权限,和拥有者的权限不一样. ...

  6. 《Linux内核设计与实现》读书笔记(十二)- 内存管理【转】

    转自:http://www.cnblogs.com/wang_yb/archive/2013/05/23/3095907.html 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己 ...

  7. 读书笔记之Linux系统编程与深入理解Linux内核

    前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...

  8. Linux内核内存管理

    <Linux内核设计与实现>读书笔记(十二)- 内存管理   内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核 ...

  9. 深入理解Linux中内存管理

    前一段时间看了<深入理解Linux内核>对其中的内存管理部分花了不少时间,但是还是有很多问题不是很清楚,最近又花了一些时间复习了一下,在这里记录下自己的理解和对Linux中内存管理的一些看 ...

随机推荐

  1. LoadRunner脚本参数化常见错误

    错误代码:Error:missing newline in d:\loadrunner\username.dat 错误原因:场景设置不合理,参数数量不够,或者参数化文件有问题. 1)如果参数化文件反复 ...

  2. Fiddler绕过前端直接和后台进行交互

    测试需求:有一个功能,允许用钻石兑换金币,假设1钻石=1金币,前端控制一次至少兑换10个,最多100个,后台不做验证. 测试方案:输入10,也就是告诉前端我要兑换10个金币,等前端验证通过之后,截取要 ...

  3. asp.net 中使用 pagedlist 分页并具有查询功能的实现方法

    用pagedlist在项目中做分页已N次了,今天再次用实例来实现一个带查询功能的分页例子. 1.在view代码: @using PagedList.Mvc@model BGZS.Models.User ...

  4. 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。

    给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为1000. 示例 1: 输入: "babad" 输出: "bab" 注意: &quo ...

  5. 题解 P1423 【小玉在游泳】

    这道题可以用简单的蒟蒻do-while循环,方式:直到型 因为是萌新/蒟蒻,所以并不知道这道题的时间/空间复杂度是多大 脚踩std(^▽^)摩擦 #include <iostream> # ...

  6. Python敏感地址扫描和爬取工具

    0×01 说明: 为了方便信息安全测评工作,及时收集敏感地址(初衷是爬取api地址),所以写了这么个小工具.两个简单的功能(目录扫描和url地址爬取). 0×02 使用参数: python spide ...

  7. URAL1519 Formula 1 【插头dp】

    题目链接 URAL1519 题解 看题型显然插头\(dp\) 考虑如何设计状态 有这样一个方案 当我们决策到某个位置 轮廓线长这样 你会发现插头一定是相互匹配的 所以我们实际上可以把状态用括号序列表示 ...

  8. HDU-3974 Assign the task题解报告【dfs序+线段树】

    There is a company that has N employees(numbered from 1 to N),every employee in the company has a im ...

  9. SCOI2014极水的题解- -

    话说SCOI都考了1个月了,终于拿出决心把题解补完了,但都说了是极水的题解,大家就看着玩吧- - DAY1 T1:目标是找最长不降子序列,先就有一个比较显然的结论,就是假如我们要拔高区间[L, R], ...

  10. 使用Hexo搭建GitHub博客(2018年Mac版)

    关于本文 本文仅记录自己学习搭建Hexo博客之时,搭建过程中掉坑的历程总结,对零基础起步的观众朋友可能缺乏某些基础技术的指导,请优先食用下述两篇优质教程: [2018更新]小白独立搭建博客-Githu ...