您的位置:首页 > 移动开发 > IOS开发

戏说BIOS之CMOS

2009-06-04 13:41 316 查看
戏说BIOSCMOS

1. Introduction

CMOS全称为complementary metal oxide semiconductor, 翻译成中文就是互补金属氧化物半导体,它是由一颗小的纽扣电池供电的128/256 bytes ram(现在的chipset通常提供256 bytes或者更大的空间)。它主要用于存放RTC以及一些oem的系统配置信息,所以除了RTC等部分其它的很多信息都是undocumented& non-standard。RTC 标准的(documented&standard) ram bank如下表 1 所示:

Index
Name
00h
Seconds
01h
Seconds Alarm
02h
Minutes
03h
Minutes Alarm
04h
Hours
05h
Hours Alarm
06h
Day of Week
07h
Day of Month
08h
Month
09h
Year
0Ah
Register A
0Bh
Register B
0Ch
Register C
0Dh
Register D
0Eh-7Fh
114 Bytes of User RAM
表 1

2. Access Cmos

访问cmos通常是透过70h,71h这两个IO port实现的,有些chipset支援256 bytes的cmos ram,访问128bytes以后的空间需要开启chipset的始能register,有些chipset使用72h,73h访问扩展的空间如intel chipset,有些仍然使用70h,71h如sis chipset,因为这部分是非标准的,故后面的练习程序就不去读写这部分ram space。读写cmos的过程非常简单,读特定的index的内容只需要将index送给70h,然后就可以从71h读出对应的数据,具体过程如下述code所示:
;-------------------------------------------------------------
; read_cmos
; read the contents of a specific CMOS register
; call with: al = CMOS address to read
; returns: ah = Contents of register
; used registers: ax
;-------------------------------------------------------------

read_cmos proc near

cli
or al,80h ;disable NMI
out 70h, al
call io_delay
in al, 71h
call io_delay
mov ah, al
xor al,al
out 70h,al ;enable NMI
sti
ret

read_cmos endp
写操作和读类似,只是要将待写入的数据送给71h即可代码如下所示:
;-------------------------------------------------------------
; write_cmos
; write the contents of a specific CMOS register
; call with: al = CMOS address to write
; ah = Contents of register
; returns: NULL
; used registers: ax
;-------------------------------------------------------------

write_cmos proc near

cli
or al,80h ;disable NMI
out 70h,al
call io_delay
mov al,ah
out 71h,al
call io_delay
xor al,al
out 70h,al ;enable NMI
sti
ret

write_cmos endp

另外有些细节需要注意:a.读写过程中都需要关掉中断以防止,中断处理程序访问CMOS以及RTC更新过程中可能会导致并发访问。b.NMI(non-maskable interrupt)是一种中断向量为2的中断,但是与常规中断不同的是它不能通过mask register屏蔽掉而且sti,cli指令也对它无效;NMI通常用于一些无法恢复的硬件错误,访问CMOS时也可能产生NMI,所以需要关掉。NMI可以通过70h bit7做开关。c.状态寄存器A bit7记录了RTC是否正在更新,如果正在更新则等到更新结束再去读RTC(我写的cmosdump因为偷懒没有检查这一个bitJ)。

3. Msg Based Event Driven

知道了以上的知识,我们就有能力写一个类似RU中dump cmos的工具了,下图1就是我写的cmosdump.exe:



我觉得访问cmos本身并不困难,画个UI倒是挺费劲的,一个劲狂call vbios;在完成这支tool的过程中我更深刻的体会到知识是相通的了,windows编程的经验在这里发挥了优势,为了能够动态更新,实时修改我就借鉴了windows下的“基于消息,事件驱动”的机制Mainloop->GetMsg->TranslateMsg->DispatchMsg一路下来好不快活!这部分的代码如下所示:

mainloop:
call show_index
call show_cmos
input_msg:
mov ah,0
int 16h
cmp ah,01h ;esc
je exit

cmp ah,48h ;up arrow
je up

cmp ah,50h ;down arrow
je down

cmp ah,4bh ;left arrow
je left

cmp ah,4dh ;right arrow
je right

call input_byte
cmp bl,1
jne msg_loop
mov ch,ah
mov ah,0
int 16h
cmp al,0dh ;enter
je enter
jmp msg_loop
enter:
call get_index
mov ah,ch
mov al,INDEX
call write_cmos

msg_loop:
jmp mainloop

up:
cmp ROW,MINROW
jbe roll_up
dec ROW
jmp bypass_up
roll_up:
mov ROW,MAXROW
bypass_up:
call set_cursor
jmp mainloop
down:
cmp ROW,MAXROW
jae roll_down
inc ROW
jmp bypass_down
roll_down:
mov ROW,MINROW
bypass_down:
call set_cursor
jmp mainloop
left:
cmp COL,MINCOL
jbe roll_left
sub COL,3
jmp bypass_left
roll_left:
mov COL,MAXCOL
bypass_left:
call set_cursor
jmp mainloop
right:
cmp COL,MAXCOL
jae roll_right
add COL,3
jmp bypass_right
roll_right:
mov COL,MINCOL
bypass_right:
call set_cursor

jmp mainloop

exit:
call clr_screen
mov ax,4c00h
int 21h
以上就是cmosdump.exe的核心架构J,完成以后觉得使用asm好别扭啊,可能是c/c++写的太多了,有点适应不过来了,以后还是要多写asm,增强驾驭asm的能力,让我的asm和c/c++一样熟练。最后开放cmosdump.exe完整的source code供有兴趣的朋友参考,source code和可执行文件在这里下载

Enjoy it!

That’s all!

Peter
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: