开机内存检测原理?

时间:2022-11-08 15:17:37
我们直到开机时,可以选择检测内存?想知道他的实现方法?望高手指点???

51 个解决方案

#1


就是说用汇编怎么实现?

#2


应该和spd chipset相关吧. 你说的内存检测,是指cas这样的参数吧?

#3


检测内存的大小等参数!

#4


检测内存大小就是逐块读,16K或者64K等等,读到一块全为FF的时候就说明该地址没有内存了。

#5


忘了说了,要先写入特定内容(00、55、AA等)再读出来比较。

#6


电脑启动时,在实模式下是怎么检测到内存是512M或更多的??

#7


检测内存的时候要切换到保护模式或者特殊的实模式(段限制改为4GB)。

#8


楼上能说的具体点马?

#9


检测内存大小就是逐块读,16K或者64K等等,读到一块全为FF的时候就说明该地址没有内存了。
-------
绝对不可能用这样的方法, 很多内存空间是用于memory map io的, 读出来可能就是ff, 再说这个方法读出来得花多长时间??

实际检测内存大小就是读spd 和北桥的memory controller相关的寄存器, 再根据内存的当前模式(mirror或者non-mirror)来算出来的

#10


你还别以为这样做很愚蠢,实际上电脑就是这么做的。
如果不执行写-读测试,那自检时内存故障是如何发现的呢?

下面就说一说你的疑问:
1. 系统开机进入加电自检(POST)时,所有需要占用内存地址空间的适配器(比如显卡)都是非使能的(这是设计规范要求的),所以不存在把显存之类的映射存储器认成内存的情况。
处理器自测试之后进入ROM BIOS的初始化部分,它首先检测1MB地址的常规内存,注意此时显卡还没有启用,所以检测到内存错误只能用PC喇叭报警(有些主板支持LED显示),然后它检测/初始化显卡,显卡启用之后(有问题的话也是PC喇叭响了),再进行1MB以上地址的扩展内存检测。
2. 至于慢不慢呢,你自己开机看一下不就知道了。:)
开机时显卡的版本信息之类的显示之后,有一个停顿,这就是在自检内存(1MB以上地址),一些老机器还会动态显示自检的内存数量。
在以前的老机器上,自检8MB内存都要好几秒呢。现在的双通道DDR/DDR2,自检1GB也不会超过2秒(如果CMOS设置中的Quick POST禁用的话,要慢一些,因为要进行写-读测试三次)。

再说说你的意见:
1. SPD。
以前的内存条根本就没有SPD,而且即便现在的内存条,把存储SPD的EEPROM芯片去掉也照样可以用。事实上在CMOS设置中可以忽略SPD的数据,手工设置参数(频率、CL、预充电时间等等)。
所以这一条显然不成立。

2. 内存控制器。
内存控制器根本不关心连接了多少内存,它只是控制产生地址、锁存数据、刷新信号等等。
也就是说它只对地址线、数据线、控制线进行操作。一个明显的例子就是读写不存在内存的物理地址不会产生任何错误。

#11


#12


>你还别以为这样做很愚蠢,实际上电脑就是这么做的。

呵呵,我亲手写了这些code, 所以我知道至少现在的电脑是这么作的。
多的我也不争了, 我也没有冒犯的意思, 术业有专攻,你亲自找份bios code来看看就知道了。:)

#13


HeHe...
都是讨论,不存在冒犯的问题。
就一个问题:
你如何解释内存自检时能发现故障之处呢?:)

#14


这个问题实际上有几方面,不吝鄙薄,略作小述

1。获得内存大小
这个现在的系统都是通过spd和其他一些北桥的寄存器算出来的。而不是靠读写内存试出来的。

2。检测内存
检测内存无非两种方法, 硬件检测(由芯片组提供),软件检测(就是你说的WRV的过程)。
硬件检测很少见,所以主要靠软件。内存检测不一定要发生在刚刚开机的时候,尤其是现在bios的实现都很灵活, 所以检测之前肯定有很多内存空洞,检测开始之前要计算出空洞的列表, 跳过去。其次,读写的时候不可能每个字节每个字节的读,否则速度太慢,所以即使你没有开Quick Post,也已经是在跳着读写了,那么就是说内存检测实际上并非我们想的那么准确。但是大多数情况下,即使跳着测试也已经能够反应问题了。在特殊的诊断模式下,软件会每个字节的读写,但是大多数人肯定不愿意这样漫长的等下去。所以,2秒钟测完1GDDR2内存基本是不可能的。

3。检测内存的可靠性
实际上即使每个字节读取,内存检测结果的可靠性仍然要打折扣,由于在系统中多个地方存在cache,即使你认为你写了检测的pattern进去,可能也只是在缓存里面,而很多cache你根本没有办法flush。 再说, 真的能flush,你检测内存的时间就会更长,因为flush是个很耗时的操作。

4。内存控制器
内存控制器不是只有硬件的接口还有软件的接口,芯片组会提供很多寄存器来告知内存的参数和状态。同时你也可以通过这些寄存器来设置内存工作模式(比如自动patrol,ECC错误门限)。因为现在内存控制器一般集成在北桥,所以北桥又叫MCH(Memory Controller Hub)。

#15


1. 你现在怎么又说软件检测了?

2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?

3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?

4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?

5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?:)

xor ax,ax
mov ds,ax ;segment at 0

;save data to avoid destoried by memory sizing due to wrap-around
push dword ptr ds:[0FFF8H]
push dword ptr ds:[0FFFCH]

;write a pre-defined pattern to check wrap-around
mov dword ptr ds:[0FFF8H],12345678H

mov ax,G_RAM
mov ds,ax

; Go into protected mode...

call Enable_Prot_Mode ; enable protected mode
jc Exit_Mem_Sizing

; Size extended memory from 1Mb

xor eax,eax
mov ax,10h
p48_62:
mov esi,TEST_INDEX
add esi,GDT_LOC
mov byte ptr ds:[esi+HIBASE+20000h],al
mov byte ptr ds:[esi+MSBASE+20000h],ah

mov si,TEST_INDEX
mov es,si ; es = test segment

mov dword ptr es:[0fff8h],0  ; write data to memory
mov dword ptr es:[0fffch],eax ; flush bus

cmp dword ptr ds:[0fff8h], 12345678h
jne short P48_64

cmp dword ptr es:[0fff8h],0  ; memory exist?
mov dword ptr es:[0fff8h],0  ; clear offboard latches
jne short p48_64 ; end of memory

mov dword ptr es:[0fff8h],0ffffffffh ; write data into memory
mov dword ptr es:[0fffch],eax  ; flush bus
cmp dword ptr es:[0fff8h],0ffffffffh ; memory exist??
mov dword ptr es:[0fff8h],0ffffffffh ; clear off board parity latches
jne short p48_64  ; jump if no more mem found

mov dword ptr es:[0fff8h],0   ; write data into memory
mov dword ptr es:[0fffch],eax  ; flush bus
cmp dword ptr es:[0fff8h],0   ; memory exist??
mov dword ptr es:[0fff8h],0   ; clear offboard parity latches
jne short p48_64  ; jump if no more mem found

p48_623:

inc ax ; increment 64k mem count

ifdef MAX_DRAM_SIZE
cmp ax,MAX_DRAM_SIZE ; DRAM size limit
else; MAX_DRAM_SIZE
  cmp ax,MAX_MEM_SIZE*4*4 ; (400H*16)  1Gb yet?
endif; MAX_DRAM_SIZE

jae short P48_64 ; test only up to 256Mb
jmp p48_62

; Enable parity

p48_64:

; Save amount found

sub ax,10h ; ax = no. of 64k chunk above 1M
shl eax,6 ; change to 1K
mov EXT_MEM_SIZE[bp],eax ; save memory found
cmp eax,0ffffh ; over 64Mb
jbe short @F ; No.
mov ax,0ffffh ; set 65535Kb max.
@@:
and ax,0FFC0h
mov cx,ax ; save orginial size

; Write information to the screen...

p48_65:
call Shutdown_From_Mem_Test ; back to real mode...

F000_call Ct_Ext_Mem_Limit ; limit extended size

mov EXT_MEM_FOUND[bp],ax ; save amount of memory found in CMOS
cmp cx,ax
je short @F ; extended size changed
xor ecx,ecx
mov cx,ax
mov EXT_MEM_SIZE[bp],ecx ; save memory found
@@:

; Display amount of memory

mov dx,EXT_MEM_FOUND[bp] ; get the found amount of ext. memory
mov EXT_MEMORY[bp],dx ; set value

#16


>1. 你现在怎么又说软件检测了?
我本来就说"大小"不是靠软件检测的,参见前文。

>2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?
您觉得这样抬杠有意思吗?我都说了“至少现在的电脑是这么作的”。

>3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?
您非得这么理解我的字节操作我也没有办法。

>4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?
带宽都是理论值,当然只能作为参考。你不信你就写个dos程序跑跑好了。

>5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?
不知道您这是哪里的code,哪年的code。AcpiPost.asm这个应该是Phoenix的code,不过code早就不是这个样子了, 更何况您这最多才记录64M。反正我在现在的code里面更本找不到这段。您有兴趣找份新点的code,有一种东西叫mrc不知道您听说过没有。

讨论问题欢迎, 抬杠嘛就免谈。

#17


>1. 你现在怎么又说软件检测了?
我本来就说"大小"不是靠软件检测的,参见前文。
========================================================================
读出的值和实际测试的值不一样怎么办?以哪个为准?不要忘了SPD是很容易修改的。


>2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?
您觉得这样抬杠有意思吗?我都说了“至少现在的电脑是这么作的”。
========================================================================
您这才是“抬杠”,
现在的电脑,内存没有SPD芯片也照样使用,您搞不懂吗?


>3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?
您非得这么理解我的字节操作我也没有办法。
========================================================================
那您的“字节操作”是什么意思?


>4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?
带宽都是理论值,当然只能作为参考。你不信你就写个dos程序跑跑好了。
========================================================================
首先这与DOS程序无关。
在32-bit保护模式下,即便845芯片组+DDR 266,32-bit传送的数据率也超过1GB/S。
写-读测试1GB内存不超过2秒很奇怪吗?
我写过,您呢?



>5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?
不知道您这是哪里的code,哪年的code。AcpiPost.asm这个应该是Phoenix的code,不过code早就不是这个样子了,更何况您这最多才记录64M。反正我在现在的code里面更本找不到这段。您有兴趣找份新点的code,有一种东西叫mrc不知道您听说过没有。
========================================================================
1. Phoenix早就=Award
2. 记录最多65535KB那只是存储到CMOS中的数据,不是扫描的数量。
3. 您的代码在哪里?


讨论问题欢迎, 抬杠嘛就免谈。
========================================================================
说话留尾巴是您的风格吗?:)

#18


"现在的电脑,内存没有SPD芯片也照样使用"-------不会吧?

没有spd芯片,主板按照什么参数跑啊?

#19


mcr是intel的内存管理器,这部分程序是保密的。

#20


回复人:zoologist(王朝) ( 二级(初级)) 信誉:100  2006-12-08 08:13:12  得分:0

"现在的电脑,内存没有SPD芯片也照样使用"-------不会吧?

没有spd芯片,主板按照什么参数跑啊?
========================================================================
这个没问题的,我试过。
BIOS会使用默认的参数,事实上,即便有SPD的内存条,你在CMOS设置中选择manual,自己设置频率、CL、预充电时间等参数,只要在内存的工作范围之内,也照样可用。

#21


1. 在《BIOS研发技术剖析》一书中,所列的AMI BIOS源代码,其检测内存大小的方法和我上面贴的Award BIOS中的一样。
可见这是一种普遍使用的方法。

2. Cody2k3()质疑我贴的代码是“哪里的?哪年的?”这个问题,是网上能下载到的Award BIOS 6.00PG的源码。
你说这个比较老,“code早就不是这个样子了”?
没问题。
我们就来看看比较新的系统是什么样的。
我反汇编了我用的一台电脑(PIV 775 + 925XE)的BIOS,虽然不算是很新,也还勉强算得上主流系统之一。
其BIOS中检测内存大小的方法和Award 6.0中的是一样的。
你不相信,可以自己验证一下。
在这里下载最新的BIOS:
http://tw.shuttle.com/Download/Download_File.asp?Item=SB95P%20V2
就是那个fb95s20s.bin。
这是一个512K的更新包,我们要先把最基本的BIOS解出来才能看到自检部分的代码。
用modbin之类的工具也可以,我是手工做的。
先把它改个名,因为解出来的那个基本包和它同名。
把此文件中64K(10000h)开始,长度13ab0h的部分复制出来。
这是一个lha压缩的文件,用RAR之类的工具都可以打开。
解压之后是一个128k的bin文件,就是最基本的BIOS模块了,其中就包括post的代码,在其文件偏移3a53开始的部分就是size memory的代码。
可以看出来,它和Award 6.0中的几乎一样,就是把最多检测1GB的限制去掉了。
这是我用IDA反汇编出来的代码:
seg000:35A3                 xor     ax, ax
seg000:35A5                 mov     ds, ax
seg000:35A7                 push    large [dword ptr ds:0FFF8h]
seg000:35AC                 push    large [dword ptr ds:0FFFCh]
seg000:35B1                 mov     dword ptr ds:0FFF8h, 12345678h
seg000:35BA                 mov     ax, 0
seg000:35BD                 mov     ds, ax
seg000:35BF                 call    sub_E3340
seg000:35C2                 jb      loc_E36CF
seg000:35C6                 xor     eax, eax
seg000:35C9                 mov     ax, 10h
seg000:35CC
seg000:35CC loc_E35CC:                              ; CODE XREF: seg000:3676j
seg000:35CC                 mov     ds:3001Ch, al
seg000:35D2                 mov     ds:3001Fh, ah
seg000:35D9                 mov     si, 18h
seg000:35DC                 mov     es, si
seg000:35DE                 assume es:nothing
seg000:35DE                 mov     ebx, es:0FFFCh
seg000:35E4                 mov     ecx, es:0FFF8h
seg000:35EA                 mov     dword ptr es:0FFF8h, 0
seg000:35F4                 mov     es:0FFFCh, eax
seg000:35F9                 cmp     dword ptr ds:0FFF8h, 12345678h
seg000:3602                 jnz     short loc_E3679
seg000:3604                 cmp     dword ptr es:0FFF8h, 0
seg000:360B                 mov     dword ptr es:0FFF8h, 0
seg000:3615                 jnz     short loc_E3679
seg000:3617                 mov     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:3621                 mov     es:0FFFCh, eax
seg000:3626                 cmp     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:362D                 mov     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:3637                 jnz     short loc_E3679
seg000:3639                 mov     dword ptr es:0FFF8h, 0
seg000:3643                 mov     es:0FFFCh, eax
seg000:3648                 cmp     dword ptr es:0FFF8h, 0
seg000:364F                 mov     dword ptr es:0FFF8h, 0
seg000:3659                 jnz     short loc_E3679
seg000:365B                 inc     eax
seg000:365D                 mov     es:0FFFCh, ebx
seg000:3663                 mov     es:0FFF8h, ecx
seg000:3669                 push    eax
seg000:366B                 sub     eax, 10h
seg000:366F                 call    sub_E36DF
seg000:3672                 pop     eax
seg000:3674                 jb      short loc_E3679
seg000:3676                 jmp     loc_E35CC
seg000:3679 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
seg000:3679
seg000:3679 loc_E3679:                              ; CODE XREF: seg000:3602j
seg000:3679                                         ; seg000:3615j ...
seg000:3679                 mov     es:0FFFCh, ebx
seg000:367F                 mov     es:0FFF8h, ecx
seg000:3685                 sub     eax, 10h
seg000:3689                 shl     eax, 6          ; CODE XREF: sub_F911Cp
seg000:368D                 mov     [bp+240h], eax
seg000:3692                 cmp     eax, 0FFFFh
seg000:3698                 jbe     short loc_E36A0
seg000:369A                 mov     eax, 0FFFFh
seg000:36A0
seg000:36A0 loc_E36A0:                              ; CODE XREF: seg000:3698j
seg000:36A0                 and     ax, 0FFC0h
seg000:36A3                 mov     cx, ax
seg000:36A5                 call    sub_E33C8
seg000:36A8                 push    cs
seg000:36A9                 push    offset loc_E36B7
seg000:36AC                 push    0EC31h
seg000:36AF                 push    35E5h
seg000:36B2                 jmp     far ptr 0F000h:0EC30h
seg000:36B7 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
seg000:36B7
seg000:36B7 loc_E36B7:                              ; DATA XREF: seg000:36A9o
seg000:36B7                 mov     [bp+30h], ax
seg000:36BA                 cmp     cx, ax
seg000:36BC                 jz      short loc_E36C8
seg000:36BE                 xor     ecx, ecx
seg000:36C1                 mov     cx, ax
seg000:36C3                 mov     [bp+240h], ecx
seg000:36C8
seg000:36C8 loc_E36C8:                              ; CODE XREF: seg000:36BCj
seg000:36C8                 sti
seg000:36C9                 mov     dx, [bp+30h]
seg000:36CC                 mov     [bp+17h], dx
seg000:36CF
seg000:36CF loc_E36CF:                              ; CODE XREF: seg000:35C2j
seg000:36CF                 xor     ax, ax
seg000:36D1                 mov     ds, ax
seg000:36D3                 pop     dword ptr ds:0FFFCh
seg000:36D8                 pop     dword ptr ds:0FFF8h

#22


你看看code,上面有push/pop 你觉得他是在memory sizing吗?

查查你的code看看是post 多少。

#23


没问题的,你可以对照Award 6.0中ACPIPOST.ASM中的类似部分。
之所以有PUSH/POP,是因为这是检测1MB以上的扩展内存部分,在保护模式下进行的,常规内存已经检测过,可以使用的。

#24


请Cody2k3()兄赐教一下哪种BIOS使用读SPD和内存控制器的方法确定内存大小,可能的话给出一个下载链接。
另外还请Cody2k3()兄指教一下如何从内存控制器中读出内存大小?能否贴一下相关的代码?

#25


这样的,你理解的memory sizing code和我们说的不是一个意思。

你程序运行到这里的时候,实际上已经完成了内存的初始化配置。

并且事实上内存的大小已经知道了。而我们提到的memory sizing

指的是对上述一无所知的情况下发生的。那时候,还是在rom中运行的。

#26


那个代码就是在ROM的F000段运行的,而且这就是在探测1MB以上的内存大小,不存在什么“内存的大小已经知道”的事。
你觉得反汇编看着麻烦的话,可以去看Award BIOS的源代码,Cody2k3()兄不是说他有新的代码吗。

#27


在f000段运行,不表示他在rom中运行啊~

#28


不要光说不练。:)
1. 你说这不是size memory的代码,那你至少要看懂它是什么吧?指出它为什么不是?它是什么?
2. 你的size memory的代码在哪里?什么机器?什么BIOS?把代码贴出来。

#29


delphiguy和cody2k3的不要PK了,伤和气。
delphiGuy所说的那本书我看过,BIOS内存开机检测确实是每块的去读,老机器上的话会很清楚到,内存检测到地址在迅速递增。Cody2k3()可以去看看这本书,讲的非常不错
Cody2k3() 所说的实际检测内存大小就是读spd 和北桥的memory controller相关的寄存器也是正确的,在PCI总线上的内存控制器里详细描述了内存布局和内存空洞位置大小,总共16块,而且可以通过PCI总线去访问和更改这些数据,内存控制器允许认为的修改内存空洞,改变内存布局。delphiguy()可以去看看国防科大出的那本 高性能个人计算机体系,上面很详细的讲述了关于pci总线的内存控制器。

32bits Operating System
http://www.wyos.net

#30


delphyguy:
       AMI的代码并非单纯的每块每块的读,我认为AWORD也应该不是的,因为BIOS在自检同时他要记录内存的布局,因为In15h E802号功能就提供了内存布局的信息,AMI在检测的时候检测了该块内存所位于的是哪个插槽。
       如果要获得内存布局的话,还必须得去访问内存控制器的配置空间。

#31


如有不对,请多多指正。

#32


好象可以用15号中断哦

#33


1. 只是讨论问题,不存在伤和气的问题。

2. 检测内存的时候INT 15H还不能用,而且这E8XX似乎是COMPAQ/HP机器才有的功能,我用的普通的Award BIOS都没有这功能。

3. 要看实际的代码,而不是凭自己的想象。
理论上来说,每64K,甚至每1MB只测试一个内存单元,也是能检测出内存大小的。但是这样就检测不出可能存在的内存故障了。

4. 我并不怀疑有其他的方式检测出内存大小,讨论的分歧只是在于具体的BIOS实现(到目前为止)是使用哪种方法检测的?
就我所掌握的资料和源代码/反汇编的结果,目前AMI/Award/Phoenix的BIOS代码都是采用分块写-读测试的方法,而不是读SPD/内存控制器的寄存器。
我认为,而且我也相信BIOS的作者采用这种方法是因为它更可靠。

5. 关于“读内存控制器的寄存器获取内存大小”的方法,我找不到任何资料,谁能贴个链接或者代码?


#34


内存布局的话,通过分块测试应该不能确定出详细的布局吧。
delphiguy关于你的第5个疑问,我刚才给你说的那本书你可以看看。我当时是在图书馆借的。
还有E802功能,不只是compaq/hp的机器支持,我的dell本本也支持,看文档上面所说只要是比较新的bios都支持此功能。

#35


哇,高手过招,偶菜鸟大开眼界了

#36


借用亡灵语录:初手Up

#37


to DelphiGuy()

我已经下载了你说的那个award的code,这个是99年的code,应该是430或者440芯片+Piix4的bios,不过我想你看错了地方。

如果你真对这份code有兴趣, 希望你看一下Chipboot.asm的1613行开始的code,看看具体的memory size是怎么获的得。这个时候根本还不能用push,除非你知道有一个叫CAR的东西。这里既有使用spd的方法也有不使用spd的方法,不过基本上没有人会使用非spd的方法。原因很简单, 你现在去装机, 能买到不带spd的内存吗?(如果你想抬杠,说你自己oem内存那我也没有办法)

另,E820(注意是E820不是E802)是标配,现在的bios如果不提供E820 现在的windows就别想起来。原因很简单, windows是靠这个知道内存布局的。如果你不信, 你就去反编译windows的ldr吧。

我的code不能给你,也不能贴出来,理由也很简单,主板厂商的bios code都是保密的。你要么通过熟人获得, 要么就反编译吧。

#38


1. 99年的是那个Award BIOS 6.00PG,而且这个6.0在很多PentiumII/PentiumIII/K7的主板上也有使用。
我后面贴的反汇编的版本是今年11月发布的,925主板上的,Award BIOS的版本至少是04年之后的。


2. Chipboot.asm的1613行开始的code那不是检测内存的大小,而是获取每个DIMM上的内存芯片类型。
2Mx8、4Mx16/32、8Mx8、16Mx8这些你明白是什么意思吧,是2M位的芯片、数据线宽度8位。
你没看到后面“Convert DRAM configuration to chipset encoding value”那段吗?那段代码检测出来的结果是一个字节(在DL寄存器中,高4位是DIMM1,低4位是DIMM0)用来生成1个字节的DIMM配置参数。
并不是内存的大小!
而且即便是这段代码,也不是读SPD,而是按地址线进行写-读测试,你看开头的那句“ifndef GET_DIMM_SIZE_BY_SPD”。
从1748行开始地方才是从SPD中读芯片信息。


3. 我这的好几台机器,Shuttle的875、925主板,INT 15h ax=E8xx都不支持(返回Carry位置1,ah=86),怎么Windows就照样能用呢。看来您需要去反编译Windows的ldr。:)
不过这与开机检测内存没关系,就不多说了。


4. 看来您还是在某主板厂家工作喽,那您确实需要加强业务学习,不要自己干的本行都搞不明白。这不是我打击您或者讽刺您,而是您表现出的水平确实令人无法恭维。
比如您所谓的“根本还不能用push”,就是一个典型的错误。
POST能够成功的一个必要条件就是内存的最低地址的一部分(64K,也许其他值,取决于BIOS的需要)必须可用。只有这一部分可用,POST才能继续,才会进入后续的检测(video、memory等)。检测1MB以上空间时整个常规内存都可以使用,怎么就不能PUSH/POP?
您可以查找一下“AWARD POST CODE”或者“AMI POST CODE”看看POST的执行顺序。


5. 现在我可以负责任地告诉您,我看到的这些BIOS,AMI/Award/Phoenix的,既有若干年前的,也有很新的,其POST时检测内存大小,都是通过写-读测试完成的。这是有实际的代码作为依据的,不是您说我看错了就错了的。
至于您的“保密的代码”,二进制文件总是要发布出来让用户下载的吧。
您能指出您这个与众不同的BIOS在哪里下载吗?我倒是很想领教一下。:)

#39


呵呵, 算我什么没说好了,这个话题就此打住好了。其他人如果有兴趣讨论,咱们另开话题。

#40


内存布局的话,通过分块测试应该不能确定出详细的布局吧。
delphiguy关于你的第5个疑问,我刚才给你说的那本书你可以看看。我当时是在图书馆借的。
--------

WYlslrt(), 你在图书馆借的书?你还是学生吗? 如果是, 作为学生你懂的不少了, 呵呵
说错了勿怪

#41


你看看code,上面有push/pop 你觉得他是在memory sizing吗?
----
to zoologist(),严格来说, pop和ret还是可以用的,只是push不能用,所以一般前面一段你会看到move sp,XX 和pop XX,以及jmp XX和ret的组合,呵呵。

#42


又一个南郭先生。

您不信服我没有关系,事实总要面对吧。

那个Award BIOS 6.00PG的源代码想来您也有,检测内存并动态显示容量,最后写入CMOS的代码在什么地方,您还不至于找不到,就自己去看吧。不过最好不要指鹿为马,指东指西就是指不到点子上。
您说这个老也没关系,把您的最新的BIOS的下载链接贡献出来(这总不会是机密吧),我们来研究一下这种高级技术。

另外《BIOS研发技术剖析》一书从第257页开始,建议您看看。不过您这样掌握主板厂商机密的高人估计是没兴趣看的。:)

#43


delphiGuy所说的那本书我看过,BIOS内存开机检测确实是每块的去读,老机器上的话会很清楚到,内存检测到地址在迅速递增。Cody2k3()可以去看看这本书,讲的非常不错
----
to WYlslrt(),其实这本书我很早就看过,入门必备书籍啊呵呵。不过code有点老,还是Ami core 5,现在已经是core 8了。其实当时ami放心让这本书出版,很重要原因是核心部分全是obj,没有代码,一般的主板厂商也拿不到。不至于对ami造成实质威胁。

ami比phoenix的优势就是ami的集成开发环境做的相当好用,用过的人都会印像深刻,呵呵。

#44


又一个南郭先生。
-------
to Delphyguy(),
让我们各自相信自己相信的部分好了,有什么必要争呢?打倒我又不能彰显你的英明神武,何况你一时半会儿还打不倒。我是水货自然有被老板炒鱿鱼的那一天,我不是也不至于影响到您的生计和威名,您说是不是?:)

坛子里面多得是新人,你有这个工夫去帮帮新人上路不比和我争这个有意思吗?

再说一遍, 这个问题和你的讨论已经结束了,您要是还不肯放过我,我认错还不行吗?

#45


不要玩这种无聊的把戏。
我用得着打倒您吗?
您的表现有目共睹,您倒了那是由于您的表现,而不是由于我打了您。
另外告诉您《BIOS研发技术剖析》一书是基于AMI BIOS 6.27的代码,不是什么“core 5”。
您确实是“早就看过”,已经忘到巴布亚新几内亚附近的一个地方去了吧。:)

#46


呵呵,苦笑中

#47


谢谢delphiGuy和Cody2k3()的讨论。
本人作为菜鸟已经下载了《BIOS研发技术剖析》,会好好看的。
讨论到此为止,我要结贴了。

#48


别结贴呀,我教育这个自以为是,处处摆老资格,说话留尾巴(讨论问题的时候我可以忍你,但是现在你落慌而逃还要摆个POSE,占点嘴上便宜,我还用得着对你客气?),拿不出真东西,见势不好就玩一个“我不和你争,我自然胜利”的流氓招数(你也不看看最初是我和你争还是你自己跳出来和我争啊?)的Cody2k3()还没完哪。

Cody2k3():

1. 你先仔细看看楼主的问题,不要犯了傻还自以为是;

2. Chipboot.asm的1613行开始的code那明明是探测DIMM上的芯片类型和bank数的,最后生成的1字节配置参数用来设置PCI配置寄存器,说明白一点就是用来设置内存控制器的行地址数寄存器!哪里象你说的那样“读spd 和北桥的memory controller相关的寄存器, 再根据内存的当前模式(mirror或者non-mirror)来算出来的”?你倒是说说那段代码哪里有读内存控制器的寄存器???分明是写嘛。
没错,根据芯片类型和BANK数,再加上单面/双面信息,也能获得一个DIMM上的内存容量,逐槽加起来就能知道总容量。
但可惜的是那段代码并不是干这个的,(1) 它没计算;(2) 它没保存;(3) 它没显示。
建议你认真读一下人家的代码,不要不懂装懂还自以为是。

3. 说你自以为是并没有冤枉你,在这个帖子里你一再表现出这种“特色”。
就比如说我前面贴的那个Award BIOS 6.0的一部分源码,你看了个没修改的标题注释就上来叫嚷“这最多才记录64M”,你也不好好看看代码里根据条件编译确定的最大1GB或者256MB的限制!
最无耻的是你毫无根据就说“在现在的code里面更本找不到这段”,我在很新的BIOS中找出这一段之后你又不吭声了。让你把你的牛X的BIOS代码列出来你又耍赖,来了个“保密”,我真想扇你这个不要脸的一个大嘴巴,源码保密,你TMD二进制BIOS文件也保密?不给用户下载呀???
还有,INT 15h AX=E8xx,那明明是OEM相关的调用,你却大嘴一撇就整出一个“E820(注意是E820不是E802)是标配,现在的bios如果不提供E820 现在的windows就别想起来”!
我告诉你很多的机器,包括925、945主板的很多机器都不支持这些调用,也就一些COMPAQ/HP/DELL的机器支持,还Windows起不来?你做梦哪?
你说说你无不无知啊?你自以为是、自我感觉良好到什么程度?!

别怪我在这里教训你,这是你自找的。
吸取教训,要么谦虚一点,多学多看;要么就继续老老实实当南郭先生,少说为佳,混在众人里冷不丁插一句话别人还以为你是高手呢。我看你在驱动开发网就不错嘛,每次都是放下一两句话就走。

#49


想顶很久了,虽然我不是全明白讲什么,但是怕顶的不是地方影响两位大侠讨论

从论据,论证,我顶DelphiGuy() 
藏着,以后看.

#50


疯球了。

#1


就是说用汇编怎么实现?

#2


应该和spd chipset相关吧. 你说的内存检测,是指cas这样的参数吧?

#3


检测内存的大小等参数!

#4


检测内存大小就是逐块读,16K或者64K等等,读到一块全为FF的时候就说明该地址没有内存了。

#5


忘了说了,要先写入特定内容(00、55、AA等)再读出来比较。

#6


电脑启动时,在实模式下是怎么检测到内存是512M或更多的??

#7


检测内存的时候要切换到保护模式或者特殊的实模式(段限制改为4GB)。

#8


楼上能说的具体点马?

#9


检测内存大小就是逐块读,16K或者64K等等,读到一块全为FF的时候就说明该地址没有内存了。
-------
绝对不可能用这样的方法, 很多内存空间是用于memory map io的, 读出来可能就是ff, 再说这个方法读出来得花多长时间??

实际检测内存大小就是读spd 和北桥的memory controller相关的寄存器, 再根据内存的当前模式(mirror或者non-mirror)来算出来的

#10


你还别以为这样做很愚蠢,实际上电脑就是这么做的。
如果不执行写-读测试,那自检时内存故障是如何发现的呢?

下面就说一说你的疑问:
1. 系统开机进入加电自检(POST)时,所有需要占用内存地址空间的适配器(比如显卡)都是非使能的(这是设计规范要求的),所以不存在把显存之类的映射存储器认成内存的情况。
处理器自测试之后进入ROM BIOS的初始化部分,它首先检测1MB地址的常规内存,注意此时显卡还没有启用,所以检测到内存错误只能用PC喇叭报警(有些主板支持LED显示),然后它检测/初始化显卡,显卡启用之后(有问题的话也是PC喇叭响了),再进行1MB以上地址的扩展内存检测。
2. 至于慢不慢呢,你自己开机看一下不就知道了。:)
开机时显卡的版本信息之类的显示之后,有一个停顿,这就是在自检内存(1MB以上地址),一些老机器还会动态显示自检的内存数量。
在以前的老机器上,自检8MB内存都要好几秒呢。现在的双通道DDR/DDR2,自检1GB也不会超过2秒(如果CMOS设置中的Quick POST禁用的话,要慢一些,因为要进行写-读测试三次)。

再说说你的意见:
1. SPD。
以前的内存条根本就没有SPD,而且即便现在的内存条,把存储SPD的EEPROM芯片去掉也照样可以用。事实上在CMOS设置中可以忽略SPD的数据,手工设置参数(频率、CL、预充电时间等等)。
所以这一条显然不成立。

2. 内存控制器。
内存控制器根本不关心连接了多少内存,它只是控制产生地址、锁存数据、刷新信号等等。
也就是说它只对地址线、数据线、控制线进行操作。一个明显的例子就是读写不存在内存的物理地址不会产生任何错误。

#11


#12


>你还别以为这样做很愚蠢,实际上电脑就是这么做的。

呵呵,我亲手写了这些code, 所以我知道至少现在的电脑是这么作的。
多的我也不争了, 我也没有冒犯的意思, 术业有专攻,你亲自找份bios code来看看就知道了。:)

#13


HeHe...
都是讨论,不存在冒犯的问题。
就一个问题:
你如何解释内存自检时能发现故障之处呢?:)

#14


这个问题实际上有几方面,不吝鄙薄,略作小述

1。获得内存大小
这个现在的系统都是通过spd和其他一些北桥的寄存器算出来的。而不是靠读写内存试出来的。

2。检测内存
检测内存无非两种方法, 硬件检测(由芯片组提供),软件检测(就是你说的WRV的过程)。
硬件检测很少见,所以主要靠软件。内存检测不一定要发生在刚刚开机的时候,尤其是现在bios的实现都很灵活, 所以检测之前肯定有很多内存空洞,检测开始之前要计算出空洞的列表, 跳过去。其次,读写的时候不可能每个字节每个字节的读,否则速度太慢,所以即使你没有开Quick Post,也已经是在跳着读写了,那么就是说内存检测实际上并非我们想的那么准确。但是大多数情况下,即使跳着测试也已经能够反应问题了。在特殊的诊断模式下,软件会每个字节的读写,但是大多数人肯定不愿意这样漫长的等下去。所以,2秒钟测完1GDDR2内存基本是不可能的。

3。检测内存的可靠性
实际上即使每个字节读取,内存检测结果的可靠性仍然要打折扣,由于在系统中多个地方存在cache,即使你认为你写了检测的pattern进去,可能也只是在缓存里面,而很多cache你根本没有办法flush。 再说, 真的能flush,你检测内存的时间就会更长,因为flush是个很耗时的操作。

4。内存控制器
内存控制器不是只有硬件的接口还有软件的接口,芯片组会提供很多寄存器来告知内存的参数和状态。同时你也可以通过这些寄存器来设置内存工作模式(比如自动patrol,ECC错误门限)。因为现在内存控制器一般集成在北桥,所以北桥又叫MCH(Memory Controller Hub)。

#15


1. 你现在怎么又说软件检测了?

2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?

3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?

4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?

5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?:)

xor ax,ax
mov ds,ax ;segment at 0

;save data to avoid destoried by memory sizing due to wrap-around
push dword ptr ds:[0FFF8H]
push dword ptr ds:[0FFFCH]

;write a pre-defined pattern to check wrap-around
mov dword ptr ds:[0FFF8H],12345678H

mov ax,G_RAM
mov ds,ax

; Go into protected mode...

call Enable_Prot_Mode ; enable protected mode
jc Exit_Mem_Sizing

; Size extended memory from 1Mb

xor eax,eax
mov ax,10h
p48_62:
mov esi,TEST_INDEX
add esi,GDT_LOC
mov byte ptr ds:[esi+HIBASE+20000h],al
mov byte ptr ds:[esi+MSBASE+20000h],ah

mov si,TEST_INDEX
mov es,si ; es = test segment

mov dword ptr es:[0fff8h],0  ; write data to memory
mov dword ptr es:[0fffch],eax ; flush bus

cmp dword ptr ds:[0fff8h], 12345678h
jne short P48_64

cmp dword ptr es:[0fff8h],0  ; memory exist?
mov dword ptr es:[0fff8h],0  ; clear offboard latches
jne short p48_64 ; end of memory

mov dword ptr es:[0fff8h],0ffffffffh ; write data into memory
mov dword ptr es:[0fffch],eax  ; flush bus
cmp dword ptr es:[0fff8h],0ffffffffh ; memory exist??
mov dword ptr es:[0fff8h],0ffffffffh ; clear off board parity latches
jne short p48_64  ; jump if no more mem found

mov dword ptr es:[0fff8h],0   ; write data into memory
mov dword ptr es:[0fffch],eax  ; flush bus
cmp dword ptr es:[0fff8h],0   ; memory exist??
mov dword ptr es:[0fff8h],0   ; clear offboard parity latches
jne short p48_64  ; jump if no more mem found

p48_623:

inc ax ; increment 64k mem count

ifdef MAX_DRAM_SIZE
cmp ax,MAX_DRAM_SIZE ; DRAM size limit
else; MAX_DRAM_SIZE
  cmp ax,MAX_MEM_SIZE*4*4 ; (400H*16)  1Gb yet?
endif; MAX_DRAM_SIZE

jae short P48_64 ; test only up to 256Mb
jmp p48_62

; Enable parity

p48_64:

; Save amount found

sub ax,10h ; ax = no. of 64k chunk above 1M
shl eax,6 ; change to 1K
mov EXT_MEM_SIZE[bp],eax ; save memory found
cmp eax,0ffffh ; over 64Mb
jbe short @F ; No.
mov ax,0ffffh ; set 65535Kb max.
@@:
and ax,0FFC0h
mov cx,ax ; save orginial size

; Write information to the screen...

p48_65:
call Shutdown_From_Mem_Test ; back to real mode...

F000_call Ct_Ext_Mem_Limit ; limit extended size

mov EXT_MEM_FOUND[bp],ax ; save amount of memory found in CMOS
cmp cx,ax
je short @F ; extended size changed
xor ecx,ecx
mov cx,ax
mov EXT_MEM_SIZE[bp],ecx ; save memory found
@@:

; Display amount of memory

mov dx,EXT_MEM_FOUND[bp] ; get the found amount of ext. memory
mov EXT_MEMORY[bp],dx ; set value

#16


>1. 你现在怎么又说软件检测了?
我本来就说"大小"不是靠软件检测的,参见前文。

>2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?
您觉得这样抬杠有意思吗?我都说了“至少现在的电脑是这么作的”。

>3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?
您非得这么理解我的字节操作我也没有办法。

>4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?
带宽都是理论值,当然只能作为参考。你不信你就写个dos程序跑跑好了。

>5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?
不知道您这是哪里的code,哪年的code。AcpiPost.asm这个应该是Phoenix的code,不过code早就不是这个样子了, 更何况您这最多才记录64M。反正我在现在的code里面更本找不到这段。您有兴趣找份新点的code,有一种东西叫mrc不知道您听说过没有。

讨论问题欢迎, 抬杠嘛就免谈。

#17


>1. 你现在怎么又说软件检测了?
我本来就说"大小"不是靠软件检测的,参见前文。
========================================================================
读出的值和实际测试的值不一样怎么办?以哪个为准?不要忘了SPD是很容易修改的。


>2. 按你那么说,没有SPD的内存条系统就不知道内存大小了?
您觉得这样抬杠有意思吗?我都说了“至少现在的电脑是这么作的”。
========================================================================
您这才是“抬杠”,
现在的电脑,内存没有SPD芯片也照样使用,您搞不懂吗?


>3. 谁说要字节操作呢?在16-bit处理器上都可以字操作,32-bit处理器上进行双字读写不是很快吗?
您非得这么理解我的字节操作我也没有办法。
========================================================================
那您的“字节操作”是什么意思?


>4. 双通道DDR 400/DDR2 533的带宽是多少?你为什么说2秒检测不完呢?你写过测试吗?
带宽都是理论值,当然只能作为参考。你不信你就写个dos程序跑跑好了。
========================================================================
首先这与DOS程序无关。
在32-bit保护模式下,即便845芯片组+DDR 266,32-bit传送的数据率也超过1GB/S。
写-读测试1GB内存不超过2秒很奇怪吗?
我写过,您呢?



>5. 我有源代码啊,在ACPIPOST.ASM中,你如何解释它的检测方法?
不知道您这是哪里的code,哪年的code。AcpiPost.asm这个应该是Phoenix的code,不过code早就不是这个样子了,更何况您这最多才记录64M。反正我在现在的code里面更本找不到这段。您有兴趣找份新点的code,有一种东西叫mrc不知道您听说过没有。
========================================================================
1. Phoenix早就=Award
2. 记录最多65535KB那只是存储到CMOS中的数据,不是扫描的数量。
3. 您的代码在哪里?


讨论问题欢迎, 抬杠嘛就免谈。
========================================================================
说话留尾巴是您的风格吗?:)

#18


"现在的电脑,内存没有SPD芯片也照样使用"-------不会吧?

没有spd芯片,主板按照什么参数跑啊?

#19


mcr是intel的内存管理器,这部分程序是保密的。

#20


回复人:zoologist(王朝) ( 二级(初级)) 信誉:100  2006-12-08 08:13:12  得分:0

"现在的电脑,内存没有SPD芯片也照样使用"-------不会吧?

没有spd芯片,主板按照什么参数跑啊?
========================================================================
这个没问题的,我试过。
BIOS会使用默认的参数,事实上,即便有SPD的内存条,你在CMOS设置中选择manual,自己设置频率、CL、预充电时间等参数,只要在内存的工作范围之内,也照样可用。

#21


1. 在《BIOS研发技术剖析》一书中,所列的AMI BIOS源代码,其检测内存大小的方法和我上面贴的Award BIOS中的一样。
可见这是一种普遍使用的方法。

2. Cody2k3()质疑我贴的代码是“哪里的?哪年的?”这个问题,是网上能下载到的Award BIOS 6.00PG的源码。
你说这个比较老,“code早就不是这个样子了”?
没问题。
我们就来看看比较新的系统是什么样的。
我反汇编了我用的一台电脑(PIV 775 + 925XE)的BIOS,虽然不算是很新,也还勉强算得上主流系统之一。
其BIOS中检测内存大小的方法和Award 6.0中的是一样的。
你不相信,可以自己验证一下。
在这里下载最新的BIOS:
http://tw.shuttle.com/Download/Download_File.asp?Item=SB95P%20V2
就是那个fb95s20s.bin。
这是一个512K的更新包,我们要先把最基本的BIOS解出来才能看到自检部分的代码。
用modbin之类的工具也可以,我是手工做的。
先把它改个名,因为解出来的那个基本包和它同名。
把此文件中64K(10000h)开始,长度13ab0h的部分复制出来。
这是一个lha压缩的文件,用RAR之类的工具都可以打开。
解压之后是一个128k的bin文件,就是最基本的BIOS模块了,其中就包括post的代码,在其文件偏移3a53开始的部分就是size memory的代码。
可以看出来,它和Award 6.0中的几乎一样,就是把最多检测1GB的限制去掉了。
这是我用IDA反汇编出来的代码:
seg000:35A3                 xor     ax, ax
seg000:35A5                 mov     ds, ax
seg000:35A7                 push    large [dword ptr ds:0FFF8h]
seg000:35AC                 push    large [dword ptr ds:0FFFCh]
seg000:35B1                 mov     dword ptr ds:0FFF8h, 12345678h
seg000:35BA                 mov     ax, 0
seg000:35BD                 mov     ds, ax
seg000:35BF                 call    sub_E3340
seg000:35C2                 jb      loc_E36CF
seg000:35C6                 xor     eax, eax
seg000:35C9                 mov     ax, 10h
seg000:35CC
seg000:35CC loc_E35CC:                              ; CODE XREF: seg000:3676j
seg000:35CC                 mov     ds:3001Ch, al
seg000:35D2                 mov     ds:3001Fh, ah
seg000:35D9                 mov     si, 18h
seg000:35DC                 mov     es, si
seg000:35DE                 assume es:nothing
seg000:35DE                 mov     ebx, es:0FFFCh
seg000:35E4                 mov     ecx, es:0FFF8h
seg000:35EA                 mov     dword ptr es:0FFF8h, 0
seg000:35F4                 mov     es:0FFFCh, eax
seg000:35F9                 cmp     dword ptr ds:0FFF8h, 12345678h
seg000:3602                 jnz     short loc_E3679
seg000:3604                 cmp     dword ptr es:0FFF8h, 0
seg000:360B                 mov     dword ptr es:0FFF8h, 0
seg000:3615                 jnz     short loc_E3679
seg000:3617                 mov     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:3621                 mov     es:0FFFCh, eax
seg000:3626                 cmp     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:362D                 mov     dword ptr es:0FFF8h, 0FFFFFFFFh
seg000:3637                 jnz     short loc_E3679
seg000:3639                 mov     dword ptr es:0FFF8h, 0
seg000:3643                 mov     es:0FFFCh, eax
seg000:3648                 cmp     dword ptr es:0FFF8h, 0
seg000:364F                 mov     dword ptr es:0FFF8h, 0
seg000:3659                 jnz     short loc_E3679
seg000:365B                 inc     eax
seg000:365D                 mov     es:0FFFCh, ebx
seg000:3663                 mov     es:0FFF8h, ecx
seg000:3669                 push    eax
seg000:366B                 sub     eax, 10h
seg000:366F                 call    sub_E36DF
seg000:3672                 pop     eax
seg000:3674                 jb      short loc_E3679
seg000:3676                 jmp     loc_E35CC
seg000:3679 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
seg000:3679
seg000:3679 loc_E3679:                              ; CODE XREF: seg000:3602j
seg000:3679                                         ; seg000:3615j ...
seg000:3679                 mov     es:0FFFCh, ebx
seg000:367F                 mov     es:0FFF8h, ecx
seg000:3685                 sub     eax, 10h
seg000:3689                 shl     eax, 6          ; CODE XREF: sub_F911Cp
seg000:368D                 mov     [bp+240h], eax
seg000:3692                 cmp     eax, 0FFFFh
seg000:3698                 jbe     short loc_E36A0
seg000:369A                 mov     eax, 0FFFFh
seg000:36A0
seg000:36A0 loc_E36A0:                              ; CODE XREF: seg000:3698j
seg000:36A0                 and     ax, 0FFC0h
seg000:36A3                 mov     cx, ax
seg000:36A5                 call    sub_E33C8
seg000:36A8                 push    cs
seg000:36A9                 push    offset loc_E36B7
seg000:36AC                 push    0EC31h
seg000:36AF                 push    35E5h
seg000:36B2                 jmp     far ptr 0F000h:0EC30h
seg000:36B7 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
seg000:36B7
seg000:36B7 loc_E36B7:                              ; DATA XREF: seg000:36A9o
seg000:36B7                 mov     [bp+30h], ax
seg000:36BA                 cmp     cx, ax
seg000:36BC                 jz      short loc_E36C8
seg000:36BE                 xor     ecx, ecx
seg000:36C1                 mov     cx, ax
seg000:36C3                 mov     [bp+240h], ecx
seg000:36C8
seg000:36C8 loc_E36C8:                              ; CODE XREF: seg000:36BCj
seg000:36C8                 sti
seg000:36C9                 mov     dx, [bp+30h]
seg000:36CC                 mov     [bp+17h], dx
seg000:36CF
seg000:36CF loc_E36CF:                              ; CODE XREF: seg000:35C2j
seg000:36CF                 xor     ax, ax
seg000:36D1                 mov     ds, ax
seg000:36D3                 pop     dword ptr ds:0FFFCh
seg000:36D8                 pop     dword ptr ds:0FFF8h

#22


你看看code,上面有push/pop 你觉得他是在memory sizing吗?

查查你的code看看是post 多少。

#23


没问题的,你可以对照Award 6.0中ACPIPOST.ASM中的类似部分。
之所以有PUSH/POP,是因为这是检测1MB以上的扩展内存部分,在保护模式下进行的,常规内存已经检测过,可以使用的。

#24


请Cody2k3()兄赐教一下哪种BIOS使用读SPD和内存控制器的方法确定内存大小,可能的话给出一个下载链接。
另外还请Cody2k3()兄指教一下如何从内存控制器中读出内存大小?能否贴一下相关的代码?

#25


这样的,你理解的memory sizing code和我们说的不是一个意思。

你程序运行到这里的时候,实际上已经完成了内存的初始化配置。

并且事实上内存的大小已经知道了。而我们提到的memory sizing

指的是对上述一无所知的情况下发生的。那时候,还是在rom中运行的。

#26


那个代码就是在ROM的F000段运行的,而且这就是在探测1MB以上的内存大小,不存在什么“内存的大小已经知道”的事。
你觉得反汇编看着麻烦的话,可以去看Award BIOS的源代码,Cody2k3()兄不是说他有新的代码吗。

#27


在f000段运行,不表示他在rom中运行啊~

#28


不要光说不练。:)
1. 你说这不是size memory的代码,那你至少要看懂它是什么吧?指出它为什么不是?它是什么?
2. 你的size memory的代码在哪里?什么机器?什么BIOS?把代码贴出来。

#29


delphiguy和cody2k3的不要PK了,伤和气。
delphiGuy所说的那本书我看过,BIOS内存开机检测确实是每块的去读,老机器上的话会很清楚到,内存检测到地址在迅速递增。Cody2k3()可以去看看这本书,讲的非常不错
Cody2k3() 所说的实际检测内存大小就是读spd 和北桥的memory controller相关的寄存器也是正确的,在PCI总线上的内存控制器里详细描述了内存布局和内存空洞位置大小,总共16块,而且可以通过PCI总线去访问和更改这些数据,内存控制器允许认为的修改内存空洞,改变内存布局。delphiguy()可以去看看国防科大出的那本 高性能个人计算机体系,上面很详细的讲述了关于pci总线的内存控制器。

32bits Operating System
http://www.wyos.net

#30


delphyguy:
       AMI的代码并非单纯的每块每块的读,我认为AWORD也应该不是的,因为BIOS在自检同时他要记录内存的布局,因为In15h E802号功能就提供了内存布局的信息,AMI在检测的时候检测了该块内存所位于的是哪个插槽。
       如果要获得内存布局的话,还必须得去访问内存控制器的配置空间。

#31


如有不对,请多多指正。

#32


好象可以用15号中断哦

#33


1. 只是讨论问题,不存在伤和气的问题。

2. 检测内存的时候INT 15H还不能用,而且这E8XX似乎是COMPAQ/HP机器才有的功能,我用的普通的Award BIOS都没有这功能。

3. 要看实际的代码,而不是凭自己的想象。
理论上来说,每64K,甚至每1MB只测试一个内存单元,也是能检测出内存大小的。但是这样就检测不出可能存在的内存故障了。

4. 我并不怀疑有其他的方式检测出内存大小,讨论的分歧只是在于具体的BIOS实现(到目前为止)是使用哪种方法检测的?
就我所掌握的资料和源代码/反汇编的结果,目前AMI/Award/Phoenix的BIOS代码都是采用分块写-读测试的方法,而不是读SPD/内存控制器的寄存器。
我认为,而且我也相信BIOS的作者采用这种方法是因为它更可靠。

5. 关于“读内存控制器的寄存器获取内存大小”的方法,我找不到任何资料,谁能贴个链接或者代码?


#34


内存布局的话,通过分块测试应该不能确定出详细的布局吧。
delphiguy关于你的第5个疑问,我刚才给你说的那本书你可以看看。我当时是在图书馆借的。
还有E802功能,不只是compaq/hp的机器支持,我的dell本本也支持,看文档上面所说只要是比较新的bios都支持此功能。

#35


哇,高手过招,偶菜鸟大开眼界了

#36


借用亡灵语录:初手Up

#37


to DelphiGuy()

我已经下载了你说的那个award的code,这个是99年的code,应该是430或者440芯片+Piix4的bios,不过我想你看错了地方。

如果你真对这份code有兴趣, 希望你看一下Chipboot.asm的1613行开始的code,看看具体的memory size是怎么获的得。这个时候根本还不能用push,除非你知道有一个叫CAR的东西。这里既有使用spd的方法也有不使用spd的方法,不过基本上没有人会使用非spd的方法。原因很简单, 你现在去装机, 能买到不带spd的内存吗?(如果你想抬杠,说你自己oem内存那我也没有办法)

另,E820(注意是E820不是E802)是标配,现在的bios如果不提供E820 现在的windows就别想起来。原因很简单, windows是靠这个知道内存布局的。如果你不信, 你就去反编译windows的ldr吧。

我的code不能给你,也不能贴出来,理由也很简单,主板厂商的bios code都是保密的。你要么通过熟人获得, 要么就反编译吧。

#38


1. 99年的是那个Award BIOS 6.00PG,而且这个6.0在很多PentiumII/PentiumIII/K7的主板上也有使用。
我后面贴的反汇编的版本是今年11月发布的,925主板上的,Award BIOS的版本至少是04年之后的。


2. Chipboot.asm的1613行开始的code那不是检测内存的大小,而是获取每个DIMM上的内存芯片类型。
2Mx8、4Mx16/32、8Mx8、16Mx8这些你明白是什么意思吧,是2M位的芯片、数据线宽度8位。
你没看到后面“Convert DRAM configuration to chipset encoding value”那段吗?那段代码检测出来的结果是一个字节(在DL寄存器中,高4位是DIMM1,低4位是DIMM0)用来生成1个字节的DIMM配置参数。
并不是内存的大小!
而且即便是这段代码,也不是读SPD,而是按地址线进行写-读测试,你看开头的那句“ifndef GET_DIMM_SIZE_BY_SPD”。
从1748行开始地方才是从SPD中读芯片信息。


3. 我这的好几台机器,Shuttle的875、925主板,INT 15h ax=E8xx都不支持(返回Carry位置1,ah=86),怎么Windows就照样能用呢。看来您需要去反编译Windows的ldr。:)
不过这与开机检测内存没关系,就不多说了。


4. 看来您还是在某主板厂家工作喽,那您确实需要加强业务学习,不要自己干的本行都搞不明白。这不是我打击您或者讽刺您,而是您表现出的水平确实令人无法恭维。
比如您所谓的“根本还不能用push”,就是一个典型的错误。
POST能够成功的一个必要条件就是内存的最低地址的一部分(64K,也许其他值,取决于BIOS的需要)必须可用。只有这一部分可用,POST才能继续,才会进入后续的检测(video、memory等)。检测1MB以上空间时整个常规内存都可以使用,怎么就不能PUSH/POP?
您可以查找一下“AWARD POST CODE”或者“AMI POST CODE”看看POST的执行顺序。


5. 现在我可以负责任地告诉您,我看到的这些BIOS,AMI/Award/Phoenix的,既有若干年前的,也有很新的,其POST时检测内存大小,都是通过写-读测试完成的。这是有实际的代码作为依据的,不是您说我看错了就错了的。
至于您的“保密的代码”,二进制文件总是要发布出来让用户下载的吧。
您能指出您这个与众不同的BIOS在哪里下载吗?我倒是很想领教一下。:)

#39


呵呵, 算我什么没说好了,这个话题就此打住好了。其他人如果有兴趣讨论,咱们另开话题。

#40


内存布局的话,通过分块测试应该不能确定出详细的布局吧。
delphiguy关于你的第5个疑问,我刚才给你说的那本书你可以看看。我当时是在图书馆借的。
--------

WYlslrt(), 你在图书馆借的书?你还是学生吗? 如果是, 作为学生你懂的不少了, 呵呵
说错了勿怪

#41


你看看code,上面有push/pop 你觉得他是在memory sizing吗?
----
to zoologist(),严格来说, pop和ret还是可以用的,只是push不能用,所以一般前面一段你会看到move sp,XX 和pop XX,以及jmp XX和ret的组合,呵呵。

#42


又一个南郭先生。

您不信服我没有关系,事实总要面对吧。

那个Award BIOS 6.00PG的源代码想来您也有,检测内存并动态显示容量,最后写入CMOS的代码在什么地方,您还不至于找不到,就自己去看吧。不过最好不要指鹿为马,指东指西就是指不到点子上。
您说这个老也没关系,把您的最新的BIOS的下载链接贡献出来(这总不会是机密吧),我们来研究一下这种高级技术。

另外《BIOS研发技术剖析》一书从第257页开始,建议您看看。不过您这样掌握主板厂商机密的高人估计是没兴趣看的。:)

#43


delphiGuy所说的那本书我看过,BIOS内存开机检测确实是每块的去读,老机器上的话会很清楚到,内存检测到地址在迅速递增。Cody2k3()可以去看看这本书,讲的非常不错
----
to WYlslrt(),其实这本书我很早就看过,入门必备书籍啊呵呵。不过code有点老,还是Ami core 5,现在已经是core 8了。其实当时ami放心让这本书出版,很重要原因是核心部分全是obj,没有代码,一般的主板厂商也拿不到。不至于对ami造成实质威胁。

ami比phoenix的优势就是ami的集成开发环境做的相当好用,用过的人都会印像深刻,呵呵。

#44


又一个南郭先生。
-------
to Delphyguy(),
让我们各自相信自己相信的部分好了,有什么必要争呢?打倒我又不能彰显你的英明神武,何况你一时半会儿还打不倒。我是水货自然有被老板炒鱿鱼的那一天,我不是也不至于影响到您的生计和威名,您说是不是?:)

坛子里面多得是新人,你有这个工夫去帮帮新人上路不比和我争这个有意思吗?

再说一遍, 这个问题和你的讨论已经结束了,您要是还不肯放过我,我认错还不行吗?

#45


不要玩这种无聊的把戏。
我用得着打倒您吗?
您的表现有目共睹,您倒了那是由于您的表现,而不是由于我打了您。
另外告诉您《BIOS研发技术剖析》一书是基于AMI BIOS 6.27的代码,不是什么“core 5”。
您确实是“早就看过”,已经忘到巴布亚新几内亚附近的一个地方去了吧。:)

#46


呵呵,苦笑中

#47


谢谢delphiGuy和Cody2k3()的讨论。
本人作为菜鸟已经下载了《BIOS研发技术剖析》,会好好看的。
讨论到此为止,我要结贴了。

#48


别结贴呀,我教育这个自以为是,处处摆老资格,说话留尾巴(讨论问题的时候我可以忍你,但是现在你落慌而逃还要摆个POSE,占点嘴上便宜,我还用得着对你客气?),拿不出真东西,见势不好就玩一个“我不和你争,我自然胜利”的流氓招数(你也不看看最初是我和你争还是你自己跳出来和我争啊?)的Cody2k3()还没完哪。

Cody2k3():

1. 你先仔细看看楼主的问题,不要犯了傻还自以为是;

2. Chipboot.asm的1613行开始的code那明明是探测DIMM上的芯片类型和bank数的,最后生成的1字节配置参数用来设置PCI配置寄存器,说明白一点就是用来设置内存控制器的行地址数寄存器!哪里象你说的那样“读spd 和北桥的memory controller相关的寄存器, 再根据内存的当前模式(mirror或者non-mirror)来算出来的”?你倒是说说那段代码哪里有读内存控制器的寄存器???分明是写嘛。
没错,根据芯片类型和BANK数,再加上单面/双面信息,也能获得一个DIMM上的内存容量,逐槽加起来就能知道总容量。
但可惜的是那段代码并不是干这个的,(1) 它没计算;(2) 它没保存;(3) 它没显示。
建议你认真读一下人家的代码,不要不懂装懂还自以为是。

3. 说你自以为是并没有冤枉你,在这个帖子里你一再表现出这种“特色”。
就比如说我前面贴的那个Award BIOS 6.0的一部分源码,你看了个没修改的标题注释就上来叫嚷“这最多才记录64M”,你也不好好看看代码里根据条件编译确定的最大1GB或者256MB的限制!
最无耻的是你毫无根据就说“在现在的code里面更本找不到这段”,我在很新的BIOS中找出这一段之后你又不吭声了。让你把你的牛X的BIOS代码列出来你又耍赖,来了个“保密”,我真想扇你这个不要脸的一个大嘴巴,源码保密,你TMD二进制BIOS文件也保密?不给用户下载呀???
还有,INT 15h AX=E8xx,那明明是OEM相关的调用,你却大嘴一撇就整出一个“E820(注意是E820不是E802)是标配,现在的bios如果不提供E820 现在的windows就别想起来”!
我告诉你很多的机器,包括925、945主板的很多机器都不支持这些调用,也就一些COMPAQ/HP/DELL的机器支持,还Windows起不来?你做梦哪?
你说说你无不无知啊?你自以为是、自我感觉良好到什么程度?!

别怪我在这里教训你,这是你自找的。
吸取教训,要么谦虚一点,多学多看;要么就继续老老实实当南郭先生,少说为佳,混在众人里冷不丁插一句话别人还以为你是高手呢。我看你在驱动开发网就不错嘛,每次都是放下一两句话就走。

#49


想顶很久了,虽然我不是全明白讲什么,但是怕顶的不是地方影响两位大侠讨论

从论据,论证,我顶DelphiGuy() 
藏着,以后看.

#50


疯球了。