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的原因

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<dos.h>  
  4.   
  5. typedef unsigned long uint32;  
  6. typedef unsigned char uint8;  
  7.   
  8. #define ONEKB 1024//2^10即1Kb  
[cpp]  view plain  copy
  1. //这也是访问4GB空间的函数所需的定义  
  2. unsigned long GDT_def[] = { 0, 0, 0x0000FFFF, 0x008F9200 };  
  3. unsigned char GDT_Addr[6] = { 0 };  
  4.   
  5. uint8 Readmm8(uint32 address)   
  6. {   
  7.         uint8 temp;  
  8.         asm push eax   
  9.         asm push esi   
  10.         asm push ds   
  11.         //asm pushad;   
  12.         asm mov ax,0   
  13.         asm mov ds,ax   
  14.         asm mov esi,address   
  15.         asm mov al,[esi]  
  16.         asm mov temp,al  
  17.         //asm popad;   
  18.         asm pop ds  
  19.         asm pop esi   
  20.         asm pop eax  
  21.           
  22.         return temp;   
  23. }  
  24.   
  25. uint32 Readmm32(uint32 address)  
  26. {   
  27.           
  28.         asm push eax   
  29.         asm push esi   
  30.         asm push ds   
  31.         //asm pushad;   
  32.         asm mov ax,0   
  33.         asm mov ds,ax   
  34.         asm mov esi,address   
  35.         asm mov eax,[esi]  
  36.         asm mov address,eax   
  37.         //asm popad;   
  38.         asm pop ds  
  39.         asm pop esi   
  40.         asm pop eax   
  41.           
  42.         return address;  
  43. }   
  44. void Wirtemm32(uint32 address,uint32 localdata)   
  45. {         
  46.         asm push eax  
  47.         asm push esi   
  48.         asm push ds   
  49.         asm mov ax,0   
  50.         asm mov ds,ax   
  51.         asm mov esi,address   
  52.         asm mov eax,localdata   
  53.         asm mov [esi],eax  
  54.         asm pop ds  
  55.         asm pop esi  
  56.         asm pop eax  
  57. }  
[cpp]  view plain  copy
  1. //DOS下默认访问1M空间,以下这两个函数为了使DOS能访问到4GB内存空间  
  2. void openA20()  
  3. {   
  4.     while(inp(0x64) & 2); outp(0x64,0xd1);  
  5.     while(inp(0x64) & 2); outp(0x60,0xdf);  
  6.     while(inp(0x64) & 2); outp(0x64,0xff);  
  7. }  
  8.   
  9. void set4gb()  
  10. {   asm{  
  11.     cli  
  12.         push ds   
  13.         push es  
  14.         mov word ptr GDT_Addr[0], (2*8-1)  
  15.         mov eax,ds  
  16.         shl eax,4  
  17.         xor ebx,ebx  
  18.         mov bx,offset GDT_def  
  19.         add eax,ebx  
  20.         mov dword ptr GDT_Addr[2],eax  
  21.         lgdt fword ptr GDT_Addr  
  22.         mov bx,8  
  23.         mov eax,cr0  
  24.         or al,1  
  25.         mov cr0,eax  
  26.         jmp flush1  
  27. }  
  28. flush1: asm{  
  29.             mov ds,bx  
  30.                 mov es,bx  
  31.                 and al,0feh  
  32.                 mov cr0,eax  
  33.                 jmp flush2  
  34.         }  
  35. flush2: asm{  
  36.             pop es ; pop ds  
  37.                 sti  
  38.         }  
  39. }  
  40.   
  41. void realToProtect()  
  42. {  
  43.     openA20();  
  44.     set4gb();  
  45. }  
  46.   
  47. uint32 CheckRSDP(uint32 begin,uint32 end)//找RSDP地址  
  48. {  
  49.     int i=0;  
  50.     uint32 addr;  
  51.     uint8 signat[9] = {"RSD PTR "};//RSDP的signature  
  52.     int count=0;  
  53.   
  54.     //find RSDP(root System Description Pointer)  
  55.     for(addr=begin ; addr<=(end) ; addr+=0x10)//16 bytes boundaries  
  56.     {  
  57.         count=0;  
  58.         for(i=0 ; Readmm8(addr+i)==signat[i] ; ++i)  
  59.         {  
  60.             ++count;  
  61.             if((signat[i+1] == '\0')&&(count==8))  
  62.                 return addr;  
  63.         }  
  64.     }  
  65.   
  66.     return 0;  
  67. }  
  68.   
  69. uint32 FindRSDP()  
  70. {  
  71.     uint32 addr;  
  72.   
  73.     if((addr=CheckRSDP(0x40e&~((uint32)0x0f)+0x10,(0x40e) + (ONEKB))) == 0)//40e,16bytes align  
  74.         addr=CheckRSDP(0x0e0000,0xfffff);  
  75.   
  76.     return addr;  
  77. }  
  78.   
  79.   
  80. uint32 PrintSignat(uint32 addr)  
  81. {  
  82.     int i;  
  83.     uint8 arr[5]={0};  
  84.     uint8 brr[5] = {"FACP"};  
  85.     for(i=0 ; i<4 ; ++i)  
  86.     {  
  87.         arr[i] = Readmm8(addr+i);  
  88.         printf("%c",arr[i]);  
  89.     }  
  90.     printf(" , %llx\n",addr);  
  91.       
  92.     if(strcmp(arr,brr) == 0) //找到FADT并返回基地址  
  93.         return addr;      
  94.       
  95.     return 0;  
  96. }  
  97.   
  98. uint32 ReadEntry(uint32 addr,uint32 width)  
  99. {  
  100.     uint32 length;  
  101.     uint32 num;  
  102.     uint32 i;  
  103.     uint32 offset;  
  104.     uint32 data;  
  105.     uint32 data1 = 0;  
  106.     uint32 tmp;  
  107.       
  108.     offset=36;   //entry in offset 36  
  109.     length = Readmm32(addr+4);   //offset04,length  
  110.     num = (length-offset)/width;   //pointer 4 bytes  
  111.       
  112.     for(i=0 ; i<num ; ++i)  
  113.     {  
  114.         data = Readmm32(addr+offset);  
  115.           
  116.         if((tmp=PrintSignat(data))!=0)  
  117.             data1 = tmp;   //FADT  
  118.           
  119.         offset += width;  
  120.     }  
  121.       
  122.     return data1;  
  123. }  
[cpp]  view plain  copy
  1. //以下两个函数就是在笔记本上实现重启变关机的功能函数了(注意拔掉电源)  
[cpp]  view plain  copy
  1. uint8 CheckSum(uint32 addr)  
  2. {  
  3. uint32 i;  
  4. uint8 sum=0;  
  5. uint32 length;  
  6. length = Readmm32(addr+4);//length  
  7. for(i=0 ; i<length ; ++i)  
  8. {  
  9.     if(i == 9)  
  10.         continue;//except checksum  
  11. sum += Readmm8(addr+i);  
  12. }  
  13. return sum;  
  14. }  
  15.   
  16.   
  17. void ChangeReset(uint32 addr)//set reset to shut off,XSDT base address  
  18. {  
  19.     uint32 data;  
  20. uint32 PM1_addr;  
  21. uint8 check;  
  22. uint8 sum;  
  23.   
  24.   
  25. data = Readmm32(addr+112);//check the flag  
  26. if((data&BIT(10)) == 0)  
  27. {  
  28. printf("reset is not supported by FACP\n");  
  29. Wirtemm32(addr+112,data|BIT(10));  
  30. }  
  31. printf("FADT:%llx\n",addr);  
  32. PM1_addr = Readmm32(addr+64);//PM_CNT(1804)  
  33. printf("PM1 addr:%llx\n",PM1_addr);  
  34. Wirtemm32(addr+116+4,PM1_addr+1);  
  35. printf("reset_reg:%llx\n",Readmm32(addr+116+4));  
  36. //Wirtemm32(addr+116+8,0);//upper  
  37.   
  38. Wirtemm8(addr+128,0x3c);//address of reset_value,3c00  
  39. printf("reset_value:%x\n",Readmm8(addr+128));  
  40.     sum = CheckSum(addr);  
  41. printf("othres sum:%x\n",sum);  
  42. check = 0-sum;  
  43. printf("check:%x\n",check);  
  44.     Wirtemm8(addr+9,check);  
  45. }  
[cpp]  view plain  copy
  1. int main()  
  2. {  
  3.     uint32 RSDP_addr;  
  4.     uint32 RSDT_addr;  
  5.     uint32 XSDT_addr_low;//XHCI,64bit  
  6.     uint32 XSDT_addr_hign;  
  7.   
  8.     uint32 addr;  
  9.     uint32 tmp;  
  10.   
  11.     realToProtect();  
  12.       
  13.     printf("main\n");  
  14.     RSDP_addr = FindRSDP();  
  15.     if(RSDP_addr != 0)  
  16.         printf("the base address of RSDP:%llx\n",RSDP_addr);  
  17.     else  
  18.         printf("find RSDP error\n");  
  19.   
  20.     RSDT_addr = Readmm32(RSDP_addr+16);//0x10  
  21.     XSDT_addr_low = Readmm32(RSDP_addr+24);  
  22.     XSDT_addr_hign = Readmm32(RSDP_addr+28);//upper  
  23.       
  24.     printf("ACPI Tables:\n");  
  25.     printf("RSD PTR  , %llx\n",RSDP_addr);  
  26.     printf("RSDT , %llx\n",RSDT_addr);  
  27.     printf("XSDT , %llx\n",XSDT_addr_low);  
  28.       
  29.     //RSDT  
  30.         if((addr = ReadEntry(XSDT_addr_low,8))!=0)//addr是返回的XSDT所指向的FADT(旗下有两个table)  
  31.     {  
  32.         tmp=Readmm32(addr+36);//FACS  
  33.         PrintSignat(tmp);  
  34.           
  35.         tmp=Readmm32(addr+40);//DSDT  
  36.         PrintSignat(tmp);  
  37.     }  
  38.     else  
  39.         printf("not find\n");  
  40.           
  41.       
  42.   
  43.     return 0;  
  44. }  


 
 
 
 


运行结果

[cpp]  view plain  copy
  1.   



猜你喜欢

转载自blog.csdn.net/yuzaipiaofei/article/details/79394764
今日推荐