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

我对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-1))
        return 0;

    /*
     * 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 0;

    id_sz = (__pa(high_memory-1) <= base + size) ?
                __pa(high_memory) - base :
                size;

    if (ioremap_change_attr((unsigned long)__va(base), id_sz, flags) < 0) {
        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-1));
        return -EINVAL;
    }
    return 0;
}   

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

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

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

时间: 2024-08-07 07:51:15

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

【笔记】深入理解Linux内核--内存寻址(一)

<深入理解Linux内核>中关于内存管理一共有三章,这是其中的一章,还有第八章,讨论内核怎样给自己分配主存,以及第九章,考虑怎样给进程分配线性地址. 内存地址 -- (P40) 以下三种地址是相对与8086处理器来说的. 逻辑地址(logical address) 包含在机器语言指令中用来指定一个操作数或一条指令的地址.比如下面反汇编代码中最左边的地址即逻辑地址. 1 40052d: 55 push %rbp 2 40052e: 48 89 e5 mov %rsp,%rbp 3 400531:

【读书笔记】《Linux内核设计与实现》内核同步介绍&内核同步方法

简要做个笔记,以备忘. 需同步的原因是,我们并发访问了共享资源.我们将访问或操作共享资源的代码段称"临界区",如果两个执行线程处于同一临界区中同时执行,称"竞争条件".这里术语执行线程指任何正在执行的代码实例,如一个在内核执行的进程.一个中断处理程序或一个内核线程. 举个简单例子,i++操作.该操作可以转换为下面的机器指令序列: 1.得到当前变量i的值,并保存到一个寄存器. 2.将寄存器的值加1. 3.将i的新值写回到内存中. 当两个线程同时进入这个临界区,若i初值

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

大学跟老师做嵌入式项目,写过I2C的设备驱动,但对Linux内核的了解也仅限于此.Android系统许多导致root的漏洞都是内核中的,研究起来很有趣,但看相关的分析文章总感觉隔着一层窗户纸,不能完全理会.所以打算系统的学习一下Linux内核.买了两本书<Linux内核设计与实现(第3版)>和<深入理解Linux内核(第3版)> 0x00 一些废话 面向对象思想. Linux内核虽然是C和汇编语言写的,没有使用面向对象的语言,但里面却包含了大量面向对象的设计.比如可以把内核中的进程

【深入理解Linux内核】《第二章 内存寻址》笔记 (2014-06-28 12:38)

2.1 内存地址 逻辑地址:段+偏移 线性地址(虚拟地址) 物理地址 2.2硬件中的分段 2.2.1 段选择符和段寄存器 15                                                3  2  1   0 ------------------------------------------------|                                                    |TI |RPL  ||         索引号 

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

内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核的内存管理必须要简洁而且高效. 主要内容: 内存的管理单元 获取内存的方法 获取高端内存 内核内存的分配方式 总结 1. 内存的管理单元 内存最基本的管理单元是页,同时按照内存地址的大小,大致分为3个区. 1.1 页 页的大小与体系结构有关,在 x86 结构中一般是 4KB或者8KB. 可以通过 getconf 命令来查看系统的page的大小: [[email prote

【深入理解Linux内核】《第一章 绪论》笔记

1.商用Unix操作系统包括: - AT&T公司开发的(System V Release 4) SVR4. - 加州伯克利分校发布的4.4BSD - Dec公司(现属于HP)的Digital Unix - IBM公司的AIX - HP公司的HP-UX - Sun公司的Solaris   - Apple公司的Mac OS X 所有商业版本都是SVR4或4.4BSD的变体,并且都趋向于遵循某些通用标准:如IEEE的POSIX(Portable Operating Systems based on U

20150514我读《深入理解linux内核》之虚拟文件系统笔记

20150514我读<深入理解linux内核>之虚拟文件系统笔记 2015-05-14 Lover雪儿 虚拟文件系统所隐含的思想就是把很多不同种类的文件系统的共同信息放入内核,其中有一个字段或者函数来支持Linux所支持的所有实际文件系统所提供的任何操作.对所调用的每个读.写或者其他函数,内核都能把他们替换成支持本地Linux文件系统.NTFS文件系统,或者文件所在的任何其他文件系统的实际函数. 虚拟文件系统可以称为虚拟文件系统转换,是一个内核软件层,用来处理与Unix标准文件系统相关的所有系

Linux内核——内存管理

内存管理 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址)通常以页为单位进行处理.MMU以页大小为单位来管理系统中的页表.从虚拟内存的角度看,页就是最小单位. 32位系统:页大小4KB 64位系统:页大小8KB 在支持4KB页大小并有1GB物理内存的机器上,物理内存会被划分为262144个页.内核用 struct page 结构表示系统中的每个物理页. struct page { page_flags_t flags;   /* 表示页的状态,每

linux内核内存分配(二、struct slab和struct kmem_cache)

前一篇bloglinux内核内存分配(一.基本概念)主要是分析linux内核内存的分配和物理页分配函数接口.但是在实际的操作中,不一定所有内存申请都需要一个物理页,很多只是需要分配几K大小的内存就可以.所以就需要更小的内存分配函数.刚开始看这个有点不懂,不过懂了就很简单了.哈哈. slab思想 摘抄<深入linux设备驱动程序内核机制>的一段话:slab分配器的基本思想是,先利用页面分配器分配出单个或者一组连续的物理页面,然后在此基础上将整块页面分割成多个相等的小内存单元,以满足小内存空间分配