栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

A.1#【内存管理】——1.2 获取系统内存布局

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

A.1#【内存管理】——1.2 获取系统内存布局

1. x86 平台

E820如何从硬件获得内存布局
背景
在操作系统开始管理内存之前,首先要获取物理内存的信息,比如共有多少物理地址是可用的? 有哪些物理地址是被ACPI(Advanced Configuration and Power Interface)数据使用? 这些信息从何而来?
e820就是BIOS像x86架构(包括x86_64)上的操作系统引导程序提供物理内存信息的功能。当请求BIOS中断号15H,并且置操作码AX=E820H的时候,BIOS就会向调用者报告可用的物理地址区间等信息,e820由此得名。

什么是E820?
E820是基于X86的计算机系统的BIOS将内存映射报告给操作系统或引导加载程序的便利工具。通过将AX寄存器设置为十六进制值E820,可以通过INT15H调用对其进行访问,报告哪些内存地址范围可用,哪些保留给BIOS使用。"BIOS-e820"通常是启动Linux内核报告的第一件事,可以通过dmesg命令看到它。使用dmesg可以看到相关的信息:

hacher@reaper:~# dmesg | grep BIOS-e820
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009bbff] usable #01
[    0.000000] BIOS-e820: [mem 0x000000000009bc00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bb4f2fff] usable #02
[    0.000000] BIOS-e820: [mem 0x00000000bb4f3000-0x00000000bb532fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb533000-0x00000000bb543fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb544000-0x00000000bb554fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb555000-0x00000000bb55dfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb55e000-0x00000000bb565fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb566000-0x00000000bb57ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb580000-0x00000000bb580fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb581000-0x00000000bb58ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb590000-0x00000000bb594fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb595000-0x00000000bb59bfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb59c000-0x00000000bb59cfff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb59d000-0x00000000bb59ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5a0000-0x00000000bb5a2fff] ACPI data
[    0.000000] BIOS-e820: [mem 0x00000000bb5a3000-0x00000000bb5a7fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5a8000-0x00000000bb5b5fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb5b6000-0x00000000bb5cbfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5cc000-0x00000000bb5cdfff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb5ce000-0x00000000bfffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fed1b000-0x00000000fed1ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000ffa00000-0x00000000ffbfffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000ffe00000-0x00000000ffffffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000100000000-0x00000002bfffffff] usable #03

其中usable的区间就是实际被映射到物理内存上的地址空间,上面标注出来的{#01,#02,#03}区间,就是我主要的可用的物理地址区间。
表示
Usable:表示已经被映射到物理内存的物理地址。
Reserved:表示这些区间是没有被映射到任何地方,不能当作RAM来使用,但是Kernel可决定将该区间映射到其他地方,比如PCI设备。通过读取/proc/iomem可以查看物理地址空间的映射情况,可以知道这些reserved的空间,是如何进一步分配给不同的设备来使用的。
ACPI data:表示映射到用来存放ACPI数据的RAM空间,操作系统应该将ACPI Table读入到这个区间内。
ACPI NVS:表示映射到用来存放ACPI数据的非易失性存储空间,操作系统不能使用。
Unusable:表示检测到发生错误的物理内存。这个在上面例子里没有,因为比较少见。

随着内核的启动,内核还会修改E820的信息{#11,#12,#13}。

hacher@reaper:~# dmesg | grep e820
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009bbff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009bc00-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bb4f2fff] usable
[    0.000000] BIOS-e820: [mem 0x00000000bb4f3000-0x00000000bb532fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb533000-0x00000000bb543fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb544000-0x00000000bb554fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb555000-0x00000000bb55dfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb55e000-0x00000000bb565fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb566000-0x00000000bb57ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb580000-0x00000000bb580fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb581000-0x00000000bb58ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb590000-0x00000000bb594fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb595000-0x00000000bb59bfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb59c000-0x00000000bb59cfff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb59d000-0x00000000bb59ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5a0000-0x00000000bb5a2fff] ACPI data
[    0.000000] BIOS-e820: [mem 0x00000000bb5a3000-0x00000000bb5a7fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5a8000-0x00000000bb5b5fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb5b6000-0x00000000bb5cbfff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000bb5cc000-0x00000000bb5cdfff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x00000000bb5ce000-0x00000000bfffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fed1b000-0x00000000fed1ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000ffa00000-0x00000000ffbfffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000ffe00000-0x00000000ffffffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000100000000-0x00000002bfffffff] usable
[    0.001803] e820: update [mem 0x00000000-0x00000fff] usable ==> reserved #11
[    0.001805] e820: remove [mem 0x000a0000-0x000fffff] usable #12
[    0.002844] e820: update [mem 0xbc000000-0xffffffff] usable ==> reserved #13
[    0.449865] e820: reserve RAM buffer [mem 0x0009bc00-0x0009ffff]
[    0.449867] e820: reserve RAM buffer [mem 0xbb4f3000-0xbbffffff]

 e820是和BIOS的一个中断相关的,具体说是int 0x15。之所以叫e820是因为在用这个中断时ax必须是0xe820。这个中断的作用是得到系统的内存布局。因为系统内存会有很多段,每段的类型属性也不一样,所以这个查询是“迭代式”的,每次求得一个段。

    我们看内核源代码。主要涉及两个文件:arch/x86/boot/memory.c和arch/x86/kernel/e820_32.c。我们 已经很幸运了,这部分代码已经用C重写过了。你可能会奇怪,启动调用e820时我们还在实模式,怎么能用C呢?答案是,这里用的是16位的C。gcc早已 经支持.code16 gcc模式了。

    看detect_memory_e820()函数,里面就是e820的本质。它把int 0x15放到一个do-while循环里,每次得到的一个内存段放到struct e820entry里,而struct e820entry的结构正是e820返回结果的结构!而像其它启动时获得的结果一样,最终都会被放到boot_params里,e820被放到了 boot_params.e820_map。

如果你对struct e820entry还有疑问,你可以看一下arch/x86/kernel/e820_32.c::print_memory_map(),看看里面是怎么使用它的。

    当然了,在arch/x86/boot/memory.c里,你还会看到另外两个利用int 0x15查询内存的函数,不过用途不一样了。

附:

boot_params结构体定义,其中E820MAX定义为128:

struct e820entry {   

__u64 addr;       

__u64 size;       

__u32 type;    

} __attribute__((packed));

struct boot_params {    

struct screen_info screen_info;             

struct apm_bios_info apm_bios_info;         

__u8  _pad2[12];                    

struct ist_info ist_info;               

__u8  _pad3[16];                    

__u8  hd0_info[16];          

__u8  hd1_info[16];          

struct sys_desc_table sys_desc_table;           

__u8  _pad4[144];                   

struct edid_info edid_info;             

struct efi_info efi_info;               

......

} __attribute__((packed));

通过bios获取系统内存布局代码如下:

static int detect_memory_e820(void){  ... }

这个函数执行完毕后,boot_params.e820_map就含有了系统内存布局图。
函数关键部分解释如下:
获取启动参数 boot_params里的 e820_map数组首地址。
通过中断0x15调用bios例程获得一个内存段的信息,这条语句是按照AT&T的汇编语法格式写的,具体语法可以查看相关资料。 

2. ARM 平台

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/973412.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号