首页 > 编程资源分享区 > C/C++源代码共享 > CMOS内存的读写和修改
2006
05-26

CMOS内存的读写和修改

一、CMOS内存信息详解

一般的PC/AT、286、386、486等微机均配有CMOS芯片,CMOS芯片包含了一个实时钟和64个字节的CMOS内存。
在CMOS内存中,0-0DH为实时钟的有关信息,0E-3FH包含计算机的硬件配置信息,如常规内存的大小、扩展
内存的大小、软盘的类型、固定盘的类型及其物理参数、显示器的类型等,这些参数与计算机能否正常工作具
有密切的关系,另外还有计算机的开机口令和其它辅助设置信息。表1列出了CMOS内存各字节的用途。
表1 CMOS内存配置信息的含义
┌───┬──────┬──────────────────────┐
│地 址*│ 功 能 │ 说 明 │
├───┼──────┼──────────────────────┤
│ 0,1 │秒,秒报警 │ │
│ 2,3 │分,分报警 │ │
│ 4,5 │时,时报警 │ │
│ 6 │星期几 │ │
│7,8,9 │日,月,年 │ │
│ A │状态寄存器A │ │
│ B │状态寄存器B │ │
│ C │状态寄存器C │ │
│ D │状态寄存器D │0=电池失效,80=电池有效 │
│ E │诊断状态 │ │
│ F │关机状态 │由上电诊断定义 │
│ 10 │软驱 │高4位为A驱,低4位为B驱,0=无,1=360KB, │
│ │ │ 2=1.2KB,4=1.44KB,6=720KB │
│ 11 │保留 │ │
│ 12 │固定盘 │高4位为C驱,低4位为D驱,0=无,F=用户定义盘, │
│ │ │ 其它为系统定义盘 │
│ 13 │保留 │ │
│ 14 │设备状态 │标志驱动器数、显示器类型、有无数学处理器等 │
│ 15-16│内存 │以KB计的常规内存数,100H=256KB,200H=512KB, │
│ │ │ 280H=640KB │
│ 17-18│扩展内存 │以KB计的扩展内存数,200H=512KB,400H=1024KB等 │
│ 19 │C盘类型数 │根据具体硬盘类型而定 │
│ 1A │D盘类型数 │根据具体硬盘类型而定 │
│ 1B-1C│保留 │ │
│ 1D-1E│C盘柱体数 │1D-2CH只有当硬盘为用户自定义类型时起作用 │
│ 1F │C盘面数 │ │
│ 20-21│C盘WP │ │
│ 22-23│C盘LZ │ │
│ 24 │C盘每柱扇区 │ │
│ 25-26│D盘柱体数 │ │
│ 27 │D盘面数 │ │
│ 28-29│D盘WP │ │
│ 2A-2B│D盘LZ │ │
│ 2C │D盘每柱扇区 │ │
│ 2D │保留 │ │
│ 2E-2F│校验和 │为10-2DH共30个字节的和数,2EH为高位,2FH为低位│
│ 30-31│扩展内存 │ │
│ 32 │日期的世纪数│BCD码的世纪值,如1995年的世纪数为19 │
│ 33 │标志信息 │ │
│ 34-3F│保留 │ │
└───┴──────┴──────────────────────┘
* 地址栏均为16进制表示

二、读写CMOS内存的方法

CMOS内存的地址口和数据口的口地址分别为70H和71H。在对CMOS内存进行写操作时,首先将要写入的CMOS内
存的地址送到口地址70H,再将要写入的数据送口地址71H。在对CMOS内存进行读操作时,首先将要读出的
CMOS内存的地址送到口地址70H,再从口地址71H读出数据到AL寄存器。

三、程序设计与使用

为了方便系统信息丢失后CMOS信息的恢复,作者用TURBO C 2.0设计了一个CMOS.C的程序,它可以将
CMOS内存中的信息直接写入文件,也可以把文件中的信息写入CMOS内存,同时可以对CMOS内存中的信息进行编
辑修改,并重新写回CMOS内存。它不仅解决了没有SETUP程序的计算机在加电时不能设置CMOS内存的问题,同
时解决了CMOS信息的保存和恢复问题,是广大计算机用户的一个好帮手。
该程序的使用很简单,在DOS提示符下打CMOS,即显示该程序的使用方法,具体使用方法是:
CMOS [/开关]
开关有3个:
R — 读取CMOS内存信息,并将其存入CMOS.DAT的文件,共占64个字节。
W — 从CMOS.DAT中读取信息,并将其写入CMOS内存。注意这样写入的CMOS信息,其时间和日期是不正确的
,写完之后应当用DOS命令DATE和TIME设置正确的日期和时间。
M — 从CMOS中读取当前信息,进行修改,然后将其写入CMOS内存和CMOS.DAT的文件。

四、源程序清单

/********************************************************/
/* 程序名称: CMOS.C 1.0 */
/* 作 者: 董占山 */
/* 完成日期: 1995-10-17 */
/* 用 途: 读、写、修改CMOS内存信息 */
/* 编译方法: 用下列命令编译连接可以得到CMOS.COM: */
/* tcc -mt cmos */
/* tlink c:\tc\lib\c0t+cmos,cmos,,c:\tc\lib\cs\lib /t */
/******************************************************* */

#include <stdio.h>
#include <ctype.h>
#include <string.h>

struct hdinfo { /* 硬盘物理参数结构体 */
unsigned int Cylinder; /* 硬盘柱体数 */
unsigned char Head; /* 面数 */
unsigned int WP;
unsigned int LZ;
unsigned char Sector; /* 扇区数 */
};

struct TCMOSStruc /* CMOS RAM信息结构体 */
{
unsigned char Seconds; /* 实时钟秒数 */
unsigned char SecondAlarm; /* 秒报警 */
unsigned char Minutes; /* 实时钟分数 */
unsigned char MinuteAlarm; /* 分报警 */
unsigned char Hours; /* 实时钟小时数 */
unsigned char HourAlarm; /* 时报警 */
unsigned char DayOfWeek; /* 周几 */
unsigned char DayOfMonth; /* 号数 */
unsigned char Month; /* 月份 */
unsigned char Year; /* 年份 */
unsigned char StatusRegA; /* 状态寄存器A */
unsigned char StatusRegB; /* 状态寄存器B */
unsigned char StatusRegC; /* 状态寄存器C */
unsigned char StatusRegD; /* 状态寄存器D */
unsigned char DiagStatus; /* 诊断状态 */
unsigned char ShutDownStatus; /* 关机状态 */
struct {
unsigned FloppyDrive2 : 4;/* 第二软驱的类型 */
unsigned FloppyDrive1 : 4;/* 第一软驱的类型 */
} fd;
unsigned char Reserved1; /* 保留 */
struct {
unsigned FixedDrive2 : 4; /* 第二硬盘的类型 */
unsigned FixedDrive1 : 4; /* 第一硬盘的类型 */
} hd;
unsigned char Reserved2; /* 保留 */
struct {
unsigned diskdrv : 1; /* 磁盘驱动器 */
unsigned mpu : 1; /* 数学处理器 */
unsigned : 2; /* 保留 */
unsigned videotype : 2; /* 当前显示类型 */
unsigned numdrive : 2; /* 磁盘驱动器的数目 */
} equipment;
unsigned int RAM; /* 基本内存KB数 */
unsigned int XMS; /* 扩充内存KB数 */
unsigned char FixedDriveType1; /* 驱动器C扩展字节 */
unsigned char FixedDriveType2; /* 驱动器D扩展字节 */
unsigned int Reserved3; /* 保留 */
struct hdinfo hd1; /* 硬盘C的物理参数 */
struct hdinfo hd2; /* 硬盘D的物理参数 */
unsigned char Sys; /* 系统字节 */
unsigned int CheckSum; /* 校验和 */
unsigned int XMS1; /* 扩展内存KB数 */
unsigned char DateCentury; /* 世纪的BCD值 */
unsigned char InfoFlags; /* 信息标志 */
unsigned char Reserved4[4]; /* 保留 */
unsigned char password[8]; /* 口令字节 */
};

struct TCMOSStruc CMOSRec;

/* 获取文件名函数 */
char *getfilename()
{
char ch,flnm[80];
printf(“\nPlease input the drive name (A/B/C/D): “);
while ((ch=getchar())==’\n’);
printf(“\n”);
flnm[0]=ch;
flnm[1]=’\0′;
strcat(flnm,”:\\CMOS.DAT”);
return flnm;
}

/* 从文件(CMOS.DAT)中读出信息 */
void ReadFile()
{
FILE *f1;
char flnm[80];
strcpy(flnm,getfilename());
if ((f1 = fopen(flnm,”rb”))==NULL) { /* 打开一个二进制文件 */
printf(“File not found !”);
exit(0);
}
fread(&CMOSRec,sizeof(CMOSRec),1,f1); /* 从文件中读CMOS内存信息 */
fclose(f1);
}

/* 将从CMOS内存中读出的信息写入文件 */
void WriteFile()
{
FILE *f1;
char flnm[80];
strcpy(flnm,getfilename());
if ((f1 = fopen(flnm,”wb”))==NULL) { /* 建立一个二进制文件 */
printf(“File does not opened !”);
exit(1);
}
fwrite(&CMOSRec,sizeof(CMOSRec),1,f1) ; /* 写CMOS内存信息记录到文件 */
fclose(f1);
}

/* 从CMOS内存中读信息 */
void ReadCMOS()
{
asm mov di,offset CMOSRec
asm mov cx,0×40
asm mov ah,0
asm mov bx,0
asm mov dx,0×70 /* CMOS口地址 */
l1:
asm mov al,ah
asm out dx,al
asm inc dx
asm in al,dx
asm mov BYTE PTR [di+BX],al
asm inc ah
asm inc bx
asm dec dx
asm loop l1
}

/* 向CMOS内存写入信息 */
void WriteCMOS()
{
asm mov di,offset CMOSRec
asm MOV CX,0×40
asm MOV AH,0
asm MOV BX,0
asm MOV DX,0×70
_L1:
asm MOV AL,AH
asm OUT DX,AL
asm MOV AL,BYTE PTR [di+BX]
asm INC DX
asm OUT DX,AL
asm INC AH
asm INC BX
asm DEC dX
asm loop _L1
}

/* 显示软盘信息 */
void DisplayFloppyDrive(FloppyDriveType,Order)
unsigned char FloppyDriveType,Order;
{
if (FloppyDriveType != 0) {
printf(“\nFloppy Drive %d : “,Order);
switch (FloppyDriveType) {
case 1 : printf(“360KB 5.25′”);break;
case 2 : printf(“1.2MB 5.25′”);break;
case 4 : printf(“1.44MB 3.5′”);break;
case 6 : printf(“720KB 3.5′”);break;
}
}
}

/* 显示硬盘信息 */
void DisplayHardDiskInfo(HDType,HDInfoRec,Order)
unsigned char HDType;
struct hdinfo HDInfoRec;
unsigned char Order;
{
printf(“\nFixed Drive %d: %d”,Order,HDType);
printf(“\n Cylinder : %d”,HDInfoRec.Cylinder);
printf(“\n Head : %d”,HDInfoRec.Head);
printf(“\n Sector: %d”,HDInfoRec.Sector);
printf(“\n LZ: %d”,HDInfoRec.LZ);
printf(“\n WP: %d”,HDInfoRec.WP);
}

/* 显示CMOS内存信息 */
void DisplayCMOS()
{
int i;
printf(“\nCMOS RAM information:”);
printf(“\nDate(MM-DD-YY): %d%d-%d%d-%d%d”,CMOSRec.Month>>4,CMOSRec.Month & 0xf,
CMOSRec.DayOfMonth>>4,CMOSRec.DayOfMonth & 0xf,
CMOSRec.Year>>4,CMOSRec.Year & 0xf);
printf(“\nTime(HH:MM:SS): %d%d:%d%d:%d%d”,CMOSRec.Hours>>4,CMOSRec.Hours & 0xf,
CMOSRec.Minutes>>4,CMOSRec.Minutes & 0xf,
CMOSRec.Seconds>>4,CMOSRec.Seconds & 0xf);
printf(“\nConventional Memory: %d KB”,CMOSRec.RAM);
printf(“\nExtended Memory: %d KB”,CMOSRec.XMS);
if (CMOSRec.hd.FixedDrive1 != 0) DisplayHardDiskInfo(CMOSRec.FixedDriveType1,CMOSRec.hd1,1);

if (CMOSRec.hd.FixedDrive2 != 0) DisplayHardDiskInfo(CMOSRec.FixedDriveType2,CMOSRec.hd2,2);

DisplayFloppyDrive(CMOSRec.fd.FloppyDrive1,1);
DisplayFlop pyDrive(CMOSRec.fd.FloppyDrive2,2);
printf(“\nScan code of password:”);
for (i=0;i<8;++i) printf(” %d”,CMOSRec.password);
printf(“\nThe number of disk drives : %d”,CMOSRec.equipment.numdrive);
printf(“\nVideo Type : %d”,CMOSRec.equipment.videotype);
printf(“\nMath co-processor present :”);
if (CMOSRec.equipment.mpu==1) printf(“YES”); else printf(“NO”);
printf(“\nDisk drives : %d”,CMOSRec.equipment.diskdrv);
}

/* 修改硬盘信息 */
void ModifyHDParam(HDType,HDInfoRec,Order)
unsigned char *HDType;
struct hdinfo *HDInfoRec;
unsigned char Order;
{
int i,j;
printf(“\nType of Fixed Disk %d : (%d) : “,Order,*HDType);
scanf(“%d”,HDType);
printf(“\n Cylinder (%d) : “,HDInfoRec->Cylinder);
scanf(“%d”,&HDInfoRec->Cy linder);
printf(“\n Head (%d) : “,HDInfoRec->Head);
scanf(“%d”,&i);
HDInfoRec->H ead = i;
printf(“\n Sector (%d) : “,HDInfoRec->Sector);
scanf(“%d”,&j);
HDInfoRec-&gt ;Sector = j;
printf(“\n LZ (%d) : “,HDInfoRec->LZ);
scanf(“%d”,&HDInfoRec->LZ);
pr intf(“\n WP (%d) : “,HDInfoRec->WP);
scanf(“%d”,&HDInfoRec->WP);
}

/* 修改软盘信息 */
void ModifyFDParam(FloppyDriveType,Order)
unsigned char FloppyDriveType,Order;
{
unsigned char i;
printf(“\nFloppy Drive %d (“,Order);
switch (FloppyDriveType) {
case 1 : printf(“1—360KB 5.25′) :”);break;
case 2 : printf(“2—1.2MB 5.25′) :”);break;
case 4 : printf(“4—1.44MB 3.5′) :”);break;
case 6 : printf(“6—720KB 3.5′) :”);break;
}
while ((i=getchar())==’\n’);
if (Order==1)
CMOSRec.fd.FloppyDrive1=i;
else
CMOSRec.fd.Flo ppyDrive2=i;
}

/* 修改协处理器信息 */
void ModifyMPU()
{
char ch;
printf(“Is there a math co-processor (Y/N) :”);
while ((ch=getchar())==’\n’);
if ((ch==’Y') || (ch==’y'))
CMOSRec.equipment.mpu=1;
else
CMOSRec.equipmen t.mpu=0;
}

/* 修改CMOS内存信息 */
void ModifyCMOS()
{
unsigned int i;
unsigned char *data,temp;
data = &CMOSRec;
printf(“\nPlease input CORRECT CMOS information !!!\n”);
printf(“\nConventional Memory (%d KB) : “,CMOSRec.RAM);
scanf(“%d”,&CMOSRec.RAM);
printf(“\nEx tended Memory (%d KB) : “,CMOSRec.XMS);
scanf(“%d”,&CMOSRec.XMS);
if (CMOSRec.hd.FixedDrive1 != 0) ModifyHDParam(&CMOSRec.FixedDriveType1,&CMOSRec.hd1, 1);
if (CMOSRec.hd.FixedDrive2 != 0) ModifyHDParam(&CMOSRec.FixedDriveType2,&CMOSRec.hd2, 2);
if (CMOSRec.FixedDriveType1!=0) CMOSRec.hd.FixedDrive1 = 0xf;
if (CMOSRec.FixedDriveType2!=0) CMOSRec.hd.FixedDrive2 = 0xf;
ModifyFDParam(CMOSRec.fd.FloppyDrive1,1);
ModifyFDPar am(CMOSRec.fd.FloppyDrive2,2);
ModifyMPU();
CMOSRec.CheckS um = 0;
for (i=16;i<46;++i) CMOSRec.CheckSum+=data; /* 计算校验和 */
temp = data[46];
data[46] = data[47];
data[47] = temp;
}

/* 显示程序帮助信息 */
void help()
{
printf(“Syntex:\n”);
printf(” CMOS /R — read information from CMOS RAM \n”);
printf(” and write it to CMOS.DAT file \n”);
printf(” CMOS /W — read configuration information from CMOS.DAT\n”);
printf(” and write it to CMOS RAM\n”);
printf(” CMOS /M — modify CMOS information and save it\n”);
printf(“Floppy Drive Type:\n”);
printf(” 1 : 360KB 5.25′\n”);
printf(” 2 : 1.2MB 5.25′\n”);
printf(” 4 : 1.44MB 3.5′\n”);
printf(” 6 : 720KB 3.5′”);
}

/* 主程序 */
main(argn,argc)
char *argc[];
int argn;
{
char ch;
char *temp;
printf(“CMOS Proctector 1.00, Copyright (c) 1995 Dong Zhanshan\n”);
if (argn == 2)
{
temp = argc[1];
ch = toupper(temp[1]);
switch (ch) {
case ‘R’ : ReadCMOS(); /* 读CMOS内存信息,并写入文件 */
DisplayCMOS();
WriteFile();
break;
case ‘W’ : ReadFile(); /* 从文件中读CMOS信息,并写入CMOS内存中 */
DisplayCMOS();
WriteCMOS();
break;
case ‘M’ : ReadCMOS(); /* 读CMOS内存读取信息,并进行修改, */
ModifyCMOS();/* 然后再写回CMOS内存 */
DisplayCMOS();
WriteFile();
WriteCMOS();
break;
defa ult : help();
}
}
else help();
return 0;
}


留下一个回复