分类: C/C++
2008-03-20 17:06:11
1 开发语言分析
1. 1 汇编语言与C语言比较
传统BIOS程序的开发一般以汇编语言作为开发工具.它的优点是:代码精简,时间效率与空间效率高,比较适合于BIOS程序开发.缺点是:源程序代码冗长,使用大量标号,定义与区分工作量大,容易混淆,寄存器使用容易冲突,模块化设计功能差,软件的开发周期长.
C语言具备如下优点:模块化的设计语言易于实现算法,缩短软件的开发周期,提高软件的开发质量,便于维护、升级,易于实现图形化用户界面,实现仿真Windows界面操作,比较适合于系统软件的开发.其缺点是:对于Intel架构的C编译器,如Borland C + +等,代码的运行必须有操作系统的支持,因此,很难应用于BIOS程序开发.
目前,专门用于单片机及嵌入式系统开发的C语言已经成熟,然而还没有专门用于微机系统BIOS程序开发的C语言,使得BIOS程序的开发仍停留在使用汇编语言阶段.
然而, C语言产生的代码十分精炼,非常接近于汇编语言,如能脱离对操作系统的依赖,并与嵌入式汇编结合,更适合快速的BIOS开发.我们通过对Borland C + +产生代码进行分析找出了解决方案.
1.
Borland C + +大部分函数使用了操作系统的功能调用,而BIOS程序往往运行于操作系统装入之前,此时是无法调用操作系统功能的.因此,一般情况下,用C语言编写的程序代码是不能脱离开操作系统支持而运行的.
BIOS程序一般都固化在ROM器件中.由于器件容量小的限制,要求BIOS程序的代码要尽可能地短,而用C语言设计的程序最短也要几KB.如: Borland C + +空语句main ( ) { }在微模式下编译链接后产生的代码长度为4KB.
程序中一条有用的语句都没有,为什么会产生出4KB的代码呢?我们经过分析发现,在编译系统的lib目录下有多个扩展名为. obj的文件.其中c0 t. obj的机器码与空C程序产生的目标代码几乎一致,只是空C程序产生的可执行程序代码比c0 t. obj多了几条语句:
push bp
mov bp, sp
pop bp
ret
由此看来,任何C程序中都将包含lib目录下对应编译模式启动代码文件的代码.其中c0 t.obj为微模式的启动代码.只要将启动代码替换成适合BIOS程序设计的自编启动代码,我们称之为“BIOS启动代码”,即可实现用C语言进行BIOS程序的开发.
2 用C语言实现BIOS编程
2. 1 创建BIOS启动代码汇编源文件
扩展BIOS程序量一般在几十KB左右,可选用微模式来进行设计.其好处在于,微模式无堆栈段,可直接使用EXE2B IN. EXE将. EXE类型的文件转换为. COM类型.因. COM类型的文件无文件头PSP (程序段前缀) ,因此,便于作为固件进行固化.本题目的BIOS相关程序设计过程均采用了微模式.
为了降低代码长度,本文用自己设计的简短BIOS启动代码模块替换了Borland C + +的原有启动代码模块.方法为:将c: \borlandc \ lib \ startup目录下原启动代码汇编原文件c0. asm更名为c0. bak,重新建立扩展BIOS启动代码汇编源文件c0. asm.
为了使BIOS启动代码适合于ISA与PC I兼容的扩展BIOS设计,必须按PC I标准给出相应的PCI配置数据.例如,以PCI为载体的扩展BIOS需在BIOS代码中包含网卡的类别号(020000H)、扩展BIOS大小及PC I.以下为扩展BIOS启动代码汇编源程序:
; c0. asm
; startup code for ISA & PCI Extended BIOS.
Locals
;定义调用的C程序主函数为外部类型
extrn main: near
code seg segment byte public ’code’
assume cs: code_seg, ds: code_seg
org 0
start p roc p roc far
;扩展BIOS有效标志
db 055h, 0aah
;累加和范围: ? =ROM器件容量/512
sum range db ?
jmp begin
org 8
;扩展卡标识
db ’PCI EXTANDED BIOS’
org 18h
; PC I数据配置指针
dw offset pcir
pcir db ’PCIR’; PC I数据配置
venderid dw 0000h; PCI厂商ID
deviceid dw ?;用户自定设备ID
data pointer dw 0000h;产品数据指针
pci data len dw 0018h; PC I数据长度
pci version db 00h ; PCI版本号
;扩展卡类别为网卡
class db 00h, 00h, 02h
map len dw 0040h; BIOS代码长度
code ver dw 0000h;代码数据版本
code type db 00h;代码类型
indicator db 80h;指示器
reserved dw 0000h;保留字
;调用C程序主函数main ( )
begin: call main
;返回BIOS调用程序
retf
;累加和凑0单元,应根据计算给出该值:
; ? = 0 -所有字节之对256求余
check sum db ?
start p roc endp
code seg ends
end start p roc
2. 2 生成BIOS启动代码目标文件
在c: \ borlandc \ lib \ startup目录中有一个文件build
build
其中: libtype可取clib ()或winlib (Windows) , srcdir为原文件目录(默认“.”) , objdir为产生的obj文件目录(默认“.”).
首先将c: \borlandc \ lib目录下原有3 . obj文件更名为3 . bak,再运行如下可产生DOS下startup模块的命令:
build - c0clib c: \borlandc \ lib \ startup c: \borlandc \lib
这样便产生了适合BIOS编程的启动模块,我们称之为BIOS启动模块.此后,即可在Borland
C + +的IDE环境下用C语言编写BIOS程序了.
2. 3 编程注意事项
a.编程时还要注意不能使用产生操作系统功能调用的函数,如p rintf ( )等.为此,需自己建立一些常用的标准设备输入输出函数,这些函数应尽量使用功能调用.
b.原有C语言的一些未调用操作系统功能的函数都可以使用.如头文件为bios. h、string. h、mem. h、ctype. h、setjmp. h和stdarg. h中定义的所有函数, . h和stdlib. h中定义的部分函数.
c.变量类型除float类型不可用外,其余都可使用.这样在C程序中可以随意使用表达式进行数值运算,而不必考虑寄存器使用冲突问题.
d.对使用C语句实现有困难的操作,可在C语言中嵌入汇编代码,不过使用时要考虑寄存器冲突等问题,所以应尽量避免使用.
e.程序可按面向对象编程模式编写,但必须注意不要使用IO流.
3 扩展BIOS编程典型示例
下面给出使用Borland C + +编写的扩展BIOS程序示例,程序全部都使用C语句.该程序可固化到一片BOOT ROM中.启动时显示“HelloWorld!”后暂停,按任意键后继续引导系统.读者可根据实际需要编写诸如无盘工作站引导卡、系统还原卡和分区引导卡等各种扩展BIOS程序.
∥disp lay a character
Void dispchar ( char ch)
{
geninterrup t (0x10) ;
}
∥Wai for keyboard hit
void pause ( void)
{ AH = 0; geninterrup t (0x16) ;
}
∥Disp lay“Hello World! " void main ( void) { char
3 p =“HelloWorld! " ; while (p ) { dispchar ( 3 p +
+ ) ; } pause ( ) ;
}
4 结论
通过构建适合BIOS数据结构的启动代码并回避操作系统的功能调用,采用现有C编译器Borland C + +实现BIOS程序开发是完全可行的.本方法已成功应用于系统还原卡、终端卡的开发,源程序代码几乎全部采用C语言完成,只有少量嵌入式汇编代码.与采用汇编语言开发相比,可在极短的时间内开发出高质量的BIOS代码.