ACPI table遍历并实现重启变关机

又有时间写博客了,这次来写ACPI table的遍历,还是比较简单的

ACPI:AdvAdvanced Configuration and PowerInterfaceanced Configuration and PowerInterface,高级配置和电源管理接口

当前,ACPI的电源管理特性一般只适用便携式计算机,

ACPI Table

BIOS在开机过程中会把包在BIOS ROM中的Acpi Table 载入到RAM中,然后留下一些信息给OS来找到他们,

最简单的例子就是RSDP Structure会放在1M以下的某个位置(一般是E0000h~FFFFh,也有可能在0x40e~(0x40e+1KB)),然后OS就可以透过搜寻

Signature(某个标记字)的方式来找到其他的Acpi Table entry point。


根据ACPI spc的说明:


①ACPI table中,RSDP是找出其他table的关键


在RSDP中,有指向XSDT的指针,而XSDT自36byte后的空间,每4个byte都指向一个PCI table的基地址

现在来看RSDP的结构


signature是一个字符串,也就是每个PCI table的名字,在offset16的4bytes地方,是RSDT的基地址;offset24地方的8bytes是XSDT的基地址(高8byte为0)


②通过RSDP找到RSDT


RSDT的36byte后的空间~length,每个entry都指向一个ACPI table,length在offset4的4bytes,(length-36)/4便是RSDT所指向的table个数


③同理,通过RSDP找到XSDT


跟RSDT类似,XSDT36byte后的每个entry也都指向一个table

注:XSDT其实和RSDT相同,打印XSDT即可,现在的OS支持ACPI2.0的用的就必须是XSDT


③这是FADT结构(RSDT下),36指向FACS,40指向DSDT,这里提到一个关键的表FADT


这样,我们就能找到所有的ACPI table了

列出所有的ACPI table

//This section specifies the structure of the system description tables:
/*...........................
• Root System Description Pointer (RSDP)
• System Description Table Header
• Root System Description Table (RSDT)
• Fixed ACPI Description Table (FADT)
• Firmware ACPI Control Structure (FACS)
• Differentiated System Description Table (DSDT)
• Secondary System Description Table (SSDT)
• Multiple APIC Description Table (MADT)
• Smart Battery Table (SBST)
• Extended System Description Table (XSDT)
• Embedded Controller Boot Resources Table (ECDT)
• System Locality Distance Information Table (SLIT)
Advanced Configuration and Power Interface Specification
Hewlett-Packard/Intel/Microsoft/Phoenix/Toshiba 105
• System Resource Affinity Table (SRAT)
• Corrected Platform Error Polling Table (CPEP)
• Maximum System Characteristics Table (MSCT)
• ACPI RAS FeatureTable (RASF)
• Memory Power StateTable (MPST)
• Platform Memory Topology Table (PMTT)
• Boot Graphics Resource Table (BGRT)
• Firmware Performance Data Table (FPDT)
• Generic Timer Description Table (GTDT)
..................................*/



下面来实现重启变关机的过程

在FADT下,有控制重启的port和value,我们只需要根据FADT修改相应的值为关机的,就可以实现变重启为关机了

①来看FADT下控制重启的内容



简单来说,就是当我们在选择重新启动键的时候,BIOS会把RESET_VALUE载入到RESET_REG里,实现重启

所以我们需要做的就是把关机的信息写到RESET_VALUE,把

②这里还有一个位置,offset64的地方,有PM1a_CNT:power mangement1 control Register



实现关机就是在这个地址写0x3c00(0011 1100 0000 0000),FADT提供给了我们这个地址,就是PM1a_CNT_BLOCK,一般不支持PM1b_CNT

③我们现在来看FADT offset64的结构,通过GAS可以找到


在offset4的地方就是写3c00的地方了,也就是FADT offset 64+4,我的机子上读出来,也可以通过RW看到,这个值是1804




参考代码(bc下编译,dos下执行)

注:第一个打印ACPI table可以在笔记本或其他板子执行,但重启变关机必须在note book上执行

Windows 98是支持ACPI的第一个微软的操作系统,而支持ACPI2.0的OS必须使用的是XSDT而非RSDT,这就是我们在程序中使用的是RSDT的原因

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

typedef unsigned long uint32;
typedef unsigned char uint8;

#define ONEKB 1024//2^10即1Kb
//这也是访问4GB空间的函数所需的定义
unsigned long GDT_def[] = { 0, 0, 0x0000FFFF, 0x008F9200 };
unsigned char GDT_Addr[6] = { 0 };

uint8 Readmm8(uint32 address) 
{ 
        uint8 temp;
        asm push eax 
        asm push esi 
        asm push ds 
        //asm pushad; 
        asm mov ax,0 
        asm mov ds,ax 
        asm mov esi,address 
        asm mov al,[esi]
        asm mov temp,al
        //asm popad; 
        asm pop ds
        asm pop esi 
        asm pop eax
		
        return temp; 
}

uint32 Readmm32(uint32 address)
{ 
        
        asm push eax 
        asm push esi 
        asm push ds 
        //asm pushad; 
        asm mov ax,0 
        asm mov ds,ax 
        asm mov esi,address 
        asm mov eax,[esi]
        asm mov address,eax 
        //asm popad; 
        asm pop ds
        asm pop esi 
        asm pop eax 
		
        return address;
} 
void Wirtemm32(uint32 address,uint32 localdata) 
{       
        asm push eax
        asm push esi 
        asm push ds 
        asm mov ax,0 
        asm mov ds,ax 
        asm mov esi,address 
        asm mov eax,localdata 
        asm mov [esi],eax
        asm pop ds
        asm pop esi
        asm pop eax
}

//DOS下默认访问1M空间,以下这两个函数为了使DOS能访问到4GB内存空间
void openA20()
{ 
	while(inp(0x64) & 2); outp(0x64,0xd1);
	while(inp(0x64) & 2); outp(0x60,0xdf);
	while(inp(0x64) & 2); outp(0x64,0xff);
}

void set4gb()
{	asm{
	cli
		push ds 
		push es
		mov word ptr GDT_Addr[0], (2*8-1)
		mov eax,ds
		shl eax,4
		xor ebx,ebx
		mov bx,offset GDT_def
		add eax,ebx
		mov dword ptr GDT_Addr[2],eax
		lgdt fword ptr GDT_Addr
		mov bx,8
		mov eax,cr0
		or al,1
		mov cr0,eax
		jmp flush1
}
flush1: asm{
			mov ds,bx
				mov es,bx
				and al,0feh
				mov cr0,eax
				jmp flush2
		}
flush2: asm{
			pop es ; pop ds
				sti
		}
}

void realToProtect()
{
	openA20();
	set4gb();
}

uint32 CheckRSDP(uint32 begin,uint32 end)//找RSDP地址
{
	int i=0;
	uint32 addr;
	uint8 signat[9] = {"RSD PTR "};//RSDP的signature
	int count=0;

	//find RSDP(root System Description Pointer)
	for(addr=begin ; addr<=(end) ; addr+=0x10)//16 bytes boundaries
	{
		count=0;
	    for(i=0 ; Readmm8(addr+i)==signat[i] ; ++i)
		{
			++count;
			if((signat[i+1] == '\0')&&(count==8))
				return addr;
		}
	}

	return 0;
}

uint32 FindRSDP()
{
	uint32 addr;

	if((addr=CheckRSDP(0x40e&~((uint32)0x0f)+0x10,(0x40e) + (ONEKB))) == 0)//40e,16bytes align
		addr=CheckRSDP(0x0e0000,0xfffff);

	return addr;
}


uint32 PrintSignat(uint32 addr)
{
	int i;
	uint8 arr[5]={0};
	uint8 brr[5] = {"FACP"};
	for(i=0 ; i<4 ; ++i)
	{
		arr[i] = Readmm8(addr+i);
		printf("%c",arr[i]);
	}
	printf(" , %llx\n",addr);
	
    if(strcmp(arr,brr) == 0) //找到FADT并返回基地址
		return addr;	
	
	return 0;
}

uint32 ReadEntry(uint32 addr,uint32 width)
{
	uint32 length;
	uint32 num;
	uint32 i;
	uint32 offset;
	uint32 data;
	uint32 data1 = 0;
	uint32 tmp;
	
	offset=36;   //entry in offset 36
	length = Readmm32(addr+4);   //offset04,length
	num = (length-offset)/width;   //pointer 4 bytes
	
	for(i=0 ; i<num ; ++i)
	{
		data = Readmm32(addr+offset);
		
		if((tmp=PrintSignat(data))!=0)
			data1 = tmp;   //FADT
		
		offset += width;
	}
	
	return data1;
}


//以下两个函数就是在笔记本上实现重启变关机的功能函数了(注意拔掉电源)
uint8 CheckSum(uint32 addr)
{
uint32 i;
uint8 sum=0;
uint32 length;
length = Readmm32(addr+4);//length
for(i=0 ; i<length ; ++i)
{
	if(i == 9)
		continue;//except checksum
sum += Readmm8(addr+i);
}
return sum;
}


void ChangeReset(uint32 addr)//set reset to shut off,XSDT base address
{
    uint32 data;
uint32 PM1_addr;
uint8 check;
uint8 sum;


data = Readmm32(addr+112);//check the flag
if((data&BIT(10)) == 0)
{
printf("reset is not supported by FACP\n");
Wirtemm32(addr+112,data|BIT(10));
}
printf("FADT:%llx\n",addr);
PM1_addr = Readmm32(addr+64);//PM_CNT(1804)
printf("PM1 addr:%llx\n",PM1_addr);
Wirtemm32(addr+116+4,PM1_addr+1);
printf("reset_reg:%llx\n",Readmm32(addr+116+4));
//Wirtemm32(addr+116+8,0);//upper

Wirtemm8(addr+128,0x3c);//address of reset_value,3c00
printf("reset_value:%x\n",Readmm8(addr+128));
    sum = CheckSum(addr);
printf("othres sum:%x\n",sum);
check = 0-sum;
printf("check:%x\n",check);
    Wirtemm8(addr+9,check);
}
int main()
{
    uint32 RSDP_addr;
	uint32 RSDT_addr;
	uint32 XSDT_addr_low;//XHCI,64bit
	uint32 XSDT_addr_hign;

	uint32 addr;
	uint32 tmp;

	realToProtect();
	
	printf("main\n");
	RSDP_addr = FindRSDP();
	if(RSDP_addr != 0)
		printf("the base address of RSDP:%llx\n",RSDP_addr);
	else
		printf("find RSDP error\n");

	RSDT_addr = Readmm32(RSDP_addr+16);//0x10
	XSDT_addr_low = Readmm32(RSDP_addr+24);
	XSDT_addr_hign = Readmm32(RSDP_addr+28);//upper
	
	printf("ACPI Tables:\n");
	printf("RSD PTR  , %llx\n",RSDP_addr);
	printf("RSDT , %llx\n",RSDT_addr);
	printf("XSDT , %llx\n",XSDT_addr_low);
	
	//RSDT
        if((addr = ReadEntry(XSDT_addr_low,8))!=0)//addr是返回的XSDT所指向的FADT(旗下有两个table)
	{
		tmp=Readmm32(addr+36);//FACS
		PrintSignat(tmp);
		
		tmp=Readmm32(addr+40);//DSDT
		PrintSignat(tmp);
	}
	else
		printf("not find\n");
		
	

	return 0;
}


 
 


运行结果

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值