X86硬件底层之硬件cpu 重启&关机&开机

一、CPU重启问题

1.关于硬件重启有如下三种方式:KBC reset、PORT 92h(端口值控制SUS#)、Ware reset
在这里插入图片描述在这里插入图片描述# include <stdio.h>
#include <dos.h>
void main()
{
outportb(0x92,0x01);
outportb(0x64,0xFE);
outportb(0xcf9,0x04);
outportb(0xcf9,0x06);
}

实现循环重启并记录重启次数

**在dos中,重启之后各个寄存器的值会被clear,因此采用的思路是:创建一个文件,在文件中记录重启的次数,当重启后就读取该文件的值+1,就会避免记不到数的问题,详细如下:

#include <stdio.h>
#include <dos.h>

void main()
{
	// int date=0xFE;
	 //int IoPost=0x64;
	 int num=0;
	 FILE *fp=fopen("ACCOUNT.TXT","r");//创建一个ACCOUNT.TXT文件,r表示已经有创建的文件,没有已创建的文件可使用“w”
	 fscanf(fp,"%d",&num);//读文件
	 fclose(fp);
	 num+=1;
	printf("now reboot account is: %d\n",num);//打印重启次数
	// sleep(3);
	 fopen("account.txt","w");//打开文件
	// fputc(num,fp);//写文件
	fprintf(fp,"%d",num);
	 fclose(fp);
	// printf("now is :%d",num);
	 sleep(5);
	outport(0x64,0xFE);//使用端口port64写入0xfe实现重启
	// outportb(0x92,0x01);//同上方式,实现不同端口的重启
 	 //outportb(0xcf9,0x04);
 	// outportb(0xcf9,0x06);
	}

补充:0xcf9
在这里插入图片描述在这里插入图片描述补充:jmp ffff:0000
cpu寻址位在第一位开始ffff:0000,当寻址位在第一位的时候及0,会检测到当前地址0040:0072位是否为1234h,如果是1234h时,就不需要检测内存,如果不是1234h,就需要检测内存,就会重启
在dos中实现该方法:进入debug command -a 进入汇编
debug:
-a
-jmp ffff:0000
-
-g

二、CPU关机问题

cpu关机机制:
在这里插入图片描述在这里插入图片描述如上图:I/O Port Address:800h
offset Address:3-2h 是电源管理使能位
offset address:5-4h 是电源管理控制位

12:10位中001:是STR模式的关机
010:是STD模式的关机,从BCD码转位10进制
10010000:24
10100000:28
由此可以看出,关机位为0x805:0x28/0x24
debug实现关机只需要给端口输入值即可:o 805 28
在borland C++实现程序关机只用到了outportb()

#include <stdio.h>
#include <dos.h>
void main()
{
	 outportb(0x805,0x28);
}

三、CPU开机

在这里插入图片描述如图,同关机原理,可得到开机位在0x803:0x05(00000101:05)
如同关机一样的方法实现开机,还需要使用到RTC定时寄存器,如下表
在这里插入图片描述
在这里插入图片描述I/OPORT Address:70h&71h是实现RTC位的
70h:设置CMOS数据地址
71h:读写70hCMOS数据
可参考74h与75h,类似于70h,71h
table 9中解读信息如下
在这里插入图片描述实例一:使用borland C++实现5S倒计时关机,计时时间显示在debug card 及打印现在的时间日期

# include <stdio.h>
# include <stdlib.h>
# include <dos.h>
# include <time.h>
int Bcd_int(int bcd);
int int_bcd(int in);

int main(void)
{
   int y,m,d,h,mi,s;
   outportb(0x70,0x09);
   y=inportb(0x71);
   outportb(0x70,0x08);
   m=inportb(0x71);
   outportb(0x70,0x07);
   d=inportb(0x71);
   outportb(0x70,0x04);
   h=inportb(0x71);
   outportb(0x70,0x02);
   mi=inportb(0x71);
   outportb(0x70,0x00);
   s=inportb(0x71);

  printf("now the time is:20%x.%x.%x %x:%x:%x\n",y,m,d,h,mi,s);

  int s1,s2,s3,s4;
  s1=Bcd_int(s);
  s2=s1+5;
  s3=int_bcd(s2);
  s4=s2%10;
  int i;
  if(s1<55)
  {

	 for(i=0;;i++)
	 {
	  system("cls");
	  printf("%d\n",s1+i);
	  outportb(0x80,s1+i);
	  outportb(0x70,0x00);
	  sleep(1);
	  if(inportb(0x71)==s3)
	  {
		outportb(0x805,0x28);
	  }
	}
	
  }
  else
  {  for(i=0;;i++)
	 {
	   system("cls");
	   int s5=s1+i;
	   if(s5>59){
	   printf("%d\n",s5%10);
	   outportb(0x80,s5%10);
	   }
	   else
	   {
	   printf("%d\n",s1+i);
	   outportb(0x80,s1+i);
	   }
	   outportb(0x70,0x00);
	   sleep(1);
	   if(inportb(0x71)==s4)
	   {
		 outportb(0x805,0x28);
	   }
	 }
   }

}

//bcd->10
int Bcd_int(int bcd)
 {
  return (0xff&(bcd>>4)*10+(0x0f&bcd));
 }

 //10->bcd
 int int_bcd(int in)
 {
  return (((in/10)<<4)+(in%10));
 }

实例二:实现系统关机后30S自动开机唤醒的循环测试

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
int Bcd_int(int bcd);
int Int_bcd(int in);

//bcd->10
int Bcd_int(int bcd)
 {
  return ((bcd>>4)*10+(0x0f&bcd));
 }

 //10->bcd
 int Int_bcd(int in)
 {
  return (((in/10)<<4)+(in%10));
 }
 
void main()
{

	int num=0;
	FILE *fp=fopen("SHUTDOWN.TXT","r");
	fscanf(fp,"%d",&num);
	fclose(fp);
	num+=1;
	printf("now the number is: %5d\n",num);
	fopen("SHUTDOWN.TXT","w");
	fprintf(fp,"%d",num);
	fclose(fp);

	//获取系统时间
   int year,month,day,hour,minus,second;
   outportb(0x70,0x09);
   year=inportb(0x71);

   outportb(0x70,0x08);
   month=inportb(0x71);

   outportb(0x70,0x07);
   day=inportb(0x71);

   outportb(0x70,0x04);
   hour=inportb(0x71);

   outportb(0x70,0x02);
   minus=inportb(0x71);

   outportb(0x70,0x00);
   second=inportb(0x71);
	printf("the time is :%x.%x.%x %x:%x:%x",year,month,day,hour,minus,second);

	//系统时间转化为10进制
   //	int year_10=Bcd_int(year);
   //	int month_10=Bcd_int(month);
	int day_10=Bcd_int(day);
	int hour_10=Bcd_int(hour);
	int minus_10=Bcd_int(minus);
	int second_10=Bcd_int(second);

	//当前10进制时间重新赋值
   int second_30=second_10+15;//70
   //int second_bcd=Int_bcd(second_30);

  //将新的时间写入Alarm
   outportb(0x70,0x0B);
   outportb(0x71,0x22);
   outportb(0x803,0x05);
   int second_bcd_new;
   int minus_bcd_new=minus;
   int day_bcd_new=day;
   int hour_bcd_new=hour;
   int month_bcd_new=month;
   if(second_30>59)
   {
		 second_30=second_30-60;
		 second_bcd_new=Int_bcd(second_30);
		 minus_10=minus_10+1;
	   if(minus_10>59)
	   {
		    minus_10=minus_10-60;
		    minus_bcd_new=Int_bcd(minus_10);
		    hour_10=hour_10+1;
			 if(hour_10>23)
			 {
				  hour_10=hour_10-24;
				  hour_bcd_new=Int_bcd(hour_10);
				  day_10=day_10+1;
				 day_bcd_new=Int_bcd(day_10);	
			 }
			 hour_bcd_new=Int_bcd(hour_10);
	   }
	   minus_bcd_new=Int_bcd(minus_10);
   }
		second_bcd_new=Int_bcd(second_30);
		
		outportb(0x70,0x01);
		outportb(0x71,second_bcd_new);

		outportb(0x70,0x03);
		outportb(0x71,minus_bcd_new);

		outportb(0x70,0x05);
		outportb(0x71,hour_bcd_new);

		outportb(0x70,0x7D);
		outportb(0x71,day_bcd_new);

		outportb(0x70,0x7E);
		outportb(0x71,month_bcd_new);

	    outportb(0x70,0x09);
		outportb(0x71,year);
	   printf("the time is :%x.%x.%x %x:%x:%x",year,month_bcd_new,day_bcd_new,hour_bcd_new,minus_bcd_new,second_bcd_new);
	   	 sleep(3);

   //outportb(0x803,0x05);
   outportb(0x805,0x28);

}


本人水平有限,有不当或有错误的地方欢迎各位留言谈论,谢谢

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值