码迷,mamicode.com
首页 > 移动开发 > 详细

BIOS入门之我见-内存

时间:2016-04-29 16:29:00      阅读:817      评论:0      收藏:0      [点我收藏+]

标签:

经过前面的几篇介绍,已经搭建了基本的界面,和实现对应的键盘操作功能,接下来我们开始实现各具体的功能.本文先介绍Memory的相关知识,阐述内存空间的概念,然后介绍如何访问内存空间,并在XU中如何实现memory dump部分。

1. 内存介绍

    谈到内存,相信大部分读者第一个想到是那根在机箱里插在主板上的绿色条子(当然偶尔也能碰到红色或蓝色:)
技术分享
技术分享
  图1 常见内存条
这里先明确一下概念,内存,即内存储器,英文Memory,(所以港台同胞称其为“记忆体”)。作用是暂时存放CPU中运算数据,以及硬盘等外部存储的交换数据。其形态多是被标准化成条状,因此往往我们把它直接用等价成内存条来看了。但实际上存在一点已少盖全,比如智能手机中也是要有内存的,只是形态各异。基本功用是一致的。当然本文涉及的主要还是电脑上用到内存,即使这样,形态也有差异的。
   内存涉及到的专有名词技术术语挺多的,本文仅是把相关概念用导图梳理一下,详情网络上大把资源不再赘述。
技术分享
技术分享
 图2 内存相关概念导图

1.1 内存工作原理

    现在市面上通用的内存大都属于DRAM ,Dynamic Random Access Memory的衍生产品,如我们主流DDR内存, 是利用电容存储电荷的能力来当作存储器,通过电晶体开关来决定是输出还是写入,如果电荷多就是1,少就是0; 使用电容来做内存体积可以做到很小,但是因为电容有漏电的问题,因此必须周期性地对电容进行充电,否则内容将会消失,这个充电过程叫刷新,因为体积小容量高,成本优势等,DDR内存已经延续至4代,当然也有专门用于显存的gddr5冒出来了。
技术分享
技术分享
图3 DRAM存储原理

1.2 内存相关参数获取

        不同的主板支持的内存会有所差异,这取决于芯片组的支持范围,对于不同厂商的内存,其关键参数CL,BL等,是要根据不同平台来调整的,BIOS在初始化时,有一个重要的动作就是设置相关北桥(或内存控制器)参数。而这些参数该填多少,怎么填,一般都是交给芯片厂商提供的MRC(memory referance code)来实现的,对于板级厂商一般无需修改,但如果想突破个别限制,有时还是需要改一下的。这里还涉及到如何获取所插入的内存条的参数,前面到图中,仔细找找,能看到一个SPD的词汇,这个就是固化在内存条模组上的资料,BIOS通过I2C协议(smbus)获取其内容,从而知道如何设置对应的内存控制器了。见下图内存条组成
技术分享
技术分享
图4 内存条组成
    SPD的读写操作,属于smbus协议范畴,计划在后续章节中做介绍,这里聚焦SPD的内容,通常内存条自带SPD内容都是按照JEDEC提供的规范设计的,不同的内存条规范会有些具体差异,但有个通用的SPD规范可以供做参考,SPD General Standard, 可以到JEDEC官网下载,用来参考一下。这里不再赘述。

1.3 内存演进

内存作为计算机系统中宝贵的资源,一直得到业界长期关注推进, 由最开始的几M到目前的几十G的容量,甚至更大。早期的DIP式,到现在的模组化的内存条,经过了一系列的进化。
我们只聚焦今天的王者DRAM,有最早的SIMM 30 和FPM 平分天下,到EDO,经典的SDRAM,RDRAM的贵族崛起,再到DDR独霸天下的今天(DDR3,DDR4),只能感慨性能之差异不可同日而语。如下图所示内存进化史。
 技术分享技术分享
图5 内存发展简图

2 内存空间

 对于CPU来讲,内存就是他的柜子,因为出身不同,不同家族的CPU,其可配置的柜子是不一样的,这里就撤出一个概念,CPU有多大的活动空间来翻柜子,即CPU的寻址空间。对于X86来讲,有内存寻址和IO寻址, 本文先聚焦内存寻址空间,简称内存空间,内存空间与内存是两个概念,内存是柜子,是可以放具体东西的,是实物。而内存空间是指CPU有多大的活动范围来翻箱子,是抽象的,不能直接放东西。
技术分享
技术分享
图6 内存空间VS内存

2.1内存空间占用情况

因为历史原因,X86的内存使用分布不是连续的,表1是较典型的PC内存使用布局
表1 Physical memory layout of the PC
linear address range real-mode address range memory type use
0- 3FF 0000:0000-0000:03FF RAM real-mode interrupt vector table (IVT)
400- 4FF 0040:0000-0040:00FF BIOS data area (BDA)
500- 9FBFF 0050:0000-9000:FBFF free conventional memory (below 1 meg)
9FC00- 9FFFF 9000:FC00-9000:FFFF extended BIOS data area (EBDA)
A0000- BFFFF A000:0000-B000:FFFF video RAM VGA framebuffers
C0000- C7FFF C000:0000-C000:7FFF ROM video BIOS (32K is typical size)
C8000- EFFFF C800:0000-E000:FFFF NOTHING  
F0000- FFFFF F000:0000-F000:FFFF ROM motherboard BIOS (64K is typical size)
100000- FEBFFFFF   RAM free extended memory (1 meg and above)
FEC00000- FFFFFFFF     various motherboard BIOS, PnP NVRAM, ACPI, etc. 
早期的DOS时代,关于内存各区域有不同的叫法,这里也稍作说明。
Expanded Memory VS Extended Memory,扩充内存与扩展内存,这个容易混淆,扩充内存技术,主要是通过在常规内存开辟一个窗口映射到其他存储设备上,从而实现扩容的目的,因限制较多,所以现在基本已经不用,扩展内存,主要指1M以上的内存扩容,常规的0~640KB是DOS使用的常规内存,640KB~1MB是UMA,即 Upper Memory Area, 1MB~1MB+65519B 即为HMA,就是High Memory Area,这里为什么是1MB+655219B是因实模式下逻辑寻址最高寻址地址,FFFF:FFFF -> 10FFEF H = 1MB + 65519B, HMA的大小就是65536-16=65520 Bytes。 
技术分享
技术分享
图7 扩展内存,HMA,UMA

2.2获取内存布局信息

知道内存的大概布局和相关概念,那我们如何获取内存布局信息呢? 这个一般是操作系统或BootLoader考虑的,要和BIOS或EFI交互信息,从而知道哪段能用哪段不能用,通常我们会引述一个东西E280,这个是啥?目前最好的PC侦测内存的方式。用BIOS提供的中断INT 0x15, EAX=0xE820 命令,E820就是这么来的,实际上,这个命令返回的是一个地址,以便下次调用时继续使用,直到返回0为止。表示所有的内存使用情况反馈完毕。使用E820的汇编参考代码如下:
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx, 0x0534D4150 ; Place "SMAP" into edx
mov eax, 0xe820
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 0x15
jc short .failed ; carry set on first call means "unsupported function"
mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short .failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short .failed
jmp short .jmpin
.e820lp:
mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes again
int 0x15
jc short .e820f ; carry set means "end of list already reached"
mov edx, 0x0534D4150 ; repair potentially trashed register
.jmpin:
jcxz .skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short .skipent
.notext:
mov ecx, [es:di + 8] ; get lower uint32_t of memory region length
or ecx, [es:di + 12] ; "or" it with upper uint32_t to test for zero
jz .skipent ; if length uint64_t is 0, skip entry
inc bp ; got a good entry: ++count, move to next storage spot
add di, 24
.skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short .e820lp
.e820f:
mov [mmap_ent], bp ; store the entry count
clc ; there is "jc" on end of list to this point, so the carry must be cleared
ret
.failed:
stc ; "function unsupported" error exit
ret
如果只是获取内存大小,方法较多,比如通过CMOS的30,31 Byte,比如通过SMBios,或者INT 0x15的其他功能,AH=E801, AH=E881, 因为不是所有的主板都提供这些功能,这里不展开介绍。参考代码XU有实现E820的功能。读者可自行查阅。

2.3内存映射机制

前面已经解释内存和内存空间的区别,那么内存空间除了内存还有什么呢? 比如上面图例中的BIOS区域,也是可以通过内存空间访问地,他不算是传统意义上的内存,而是广义内存中的非失忆存储设备,一般是SPI接口的Flash(早期也有FWH的),还有些PCI设备可以通过内存访问其寄存器的,这里就涉及到各概念memory mapping。 
PCI设备寄存器map到内存空间,  Why? 1. X86的IO空间只有64K, 扣除保留的空间,实际能使用的很有限。2.CPU的IO指令存取数据很慢,用Memory方式可以很快。因此,对于需要高速、大空间的PCI设备都改成内存空间上访问其寄存器,PCI本身支持内存存取,方便转移,因此现在高速的PCI设备一般占用内存空间。
读者可能会奇怪PCI与内存之间没线路连接,怎么可以在内存空间看到PCI设备呢?这个关键在于桥片了,(南北桥时代看北桥),实际上就是内存控制器,他做了些工作,将特定的内存位置转由PCI总线传送出去,所以可以使用内存的方式操作PCI设备。
技术分享
技术分享
图8 内存映射机制
当然,不是说有的PCI设备都需要内存映射,主要取决于厂商的设计,简单的PCI设备无需,高级的复杂的比如RAID卡等需要memory mapping。

3.内存的读写操作

   前面已经将内存的基础知识做了一下回顾,下面解释CPU对于内存怎样访问读写。

3.1内存地址空间访问模式

内存地址空间的访问模式与CPU的工作模式对应的, X86因为历史原因,一直保留着实模式real mode,这时的寻址范围1 MB以下,主要是其地址线范围所限,通过段地址+偏移地址来访问内存的指定位置。
286及以后的CPU支持保护模式,286的地址上线是16MB,而之后的是4G或更大。保护模式用到了段选择子,虽然还是通过CPU的段寄存器操作,但其定义已经完全变了。
另外一种叫big real mode的模式,实际上等价于在实模式实开启了A20,使得内存线性地址与实际的物理地址一一对应,这个对于调试,内存内容比较会直观些。

3.2内存访问指令

内存的访问指令,汇编比较直接,读:mov 通用寄存器,[内存地址]  写:mov 「内存地址],通用寄存器;C语言中,用指针操作会方便些。当然我们在C中定义的变量,对其修改时其实也是最终转换成mov指令的。只是这部分工作由编译器汇编器代劳了。

3.3XU中内存访问的实现

最后,简单介绍一下XU中对内存dump功能的实现方式,前面已经说过C语言中可以通过指针来操作内存,读或写,XU中就是通过指针操作实现的,不过拥有了一个union联合来方便按Byte,Word,Dword来访问显示数据,定义如下:
union point_tag {
unsigned char *pb;
unsigned short *pw;
unsigned long *pd;
unsigned long d;
} pmem;
这样访问的是同一个地址,按小边对齐,可以访问数据的长度因为union里面的不同成员定义类型而定,这样方便后续切换操作,所访问的内存地址仍然是同一个。至于相关信息的显示内容,就不再赘述,请各位看官参考源代码吧,基本都是体力劳动了。

4.参考文献

高手进阶,终极内存技术指南——完整 赵效民 百度文库 
内存分类介绍 刘彦清 百度文库
详解内存工作原理及发展历程
Memory Map(x86)
Detecting Memory (x86)

BIOS入门之我见-内存

标签:

原文地址:http://blog.csdn.net/kevinhugh163/article/details/51264926

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!