鱼C论坛

 找回密码
 立即注册
查看: 2644|回复: 10

[已解决]代码求助

[复制链接]
发表于 2022-10-10 08:46:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
有人可以根据SMBIOS的spec来实现在Linux中查询EPS表和遍历SMBIOS信息的代码吗?
最佳答案
2022-10-10 18:11:49
#include <stdio.h>
#include <stdlib.h>

#define __USE_GNU
#include <string.h>

#include <errno.h>

int main(void) {
    FILE *fp = fopen("/dev/mem", "r");
    if(!fp) {
        int err = errno;
        perror("/dev/mem");
        exit(-err);
    }
    fseek(fp, 0xf0000, SEEK_SET);
    char buff[65536];
    fread(buff, 1, 65536, fp);
    char *eps = memmem(buff, 65536, "_SM_", 4);
    if(eps && !strncmp(eps + 16, "_DMI_", 5)) {
        eps = (char *)(eps - buff + 0xf0000);
        printf("%p\n", eps);
    }
    fclose(fp);
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-10-10 14:42:20 | 显示全部楼层
在Windows上实现也行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-10-10 16:18:45 | 显示全部楼层
类似这种 做一下改良
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#define StartAddress  0xF0000
#define EndAddress  0xFFFFF
#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

typedef unsigned long DWORD;
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;


typedef struct
{
        BYTE Type;
        BYTE Length;
        WORD Handle;
}Header;

typedef struct
{       
        BYTE Major_Version;
        BYTE Minor_Version;
        WORD Length;
        DWORD Address;
        WORD Struct_Count;
}EPS;

const char *characteristics[]={
        "Reserved", "Reserved", "Unknown", "BIOS Characteristics are not supported",
        "ISA is supported", "MICA is supported","EISA is supported","PCI is supported",
        "PC card(PCMCIA) is supported", "Plug and Play is supported",
        "APM is supported", "BIOS is upgradeable(Flash)", "BIOS shadowing is allowed",
        "VL-VESA is supported", "ESCD support is available",
        "Boot from CD is supported", "Selected boot is supported",
        "BIOS ROM is socketed", "Boot from PC card(PCMCIA)is supported",
        "EDD specification is supported",
        "Int 13h--Japanese floppy for NEC 9800 1.2 MB(3.5\",1K bytes/sector, 360 RPM)is supported",  
        "Int 13h--Japanese floppy for Toshiba 1.2 MB(3.5\", 360 RPM)is supported",
        "Int 13h--5.25\"/360 KB floppy services are supported",
        "Int 13h--5.25\"/1.2 MB floppy services are supported",
        "Int 13h--3.5\"/720 KB floppy services are supported",
        "Int 13h--5.25\"/2.88 MB floppy services are supported",
        "Int 5h, print screen Service is supported",
        "Int 9h, 8042 keyboard services are supported",
        "Int 14h, serial services are supported",
        "Int 17h, printer services are supported",
        "Int 10h, CGA/Mono Video Services are supported",
        "NEC PC-98", "Reserved for BIOS vendor", "Reserved for system vendor"
};

const char *characteristics_ex[]={
        "ACPI is supported", "USB Legacy is supported", "AGP is supported",
        "I2O boot is supported", "LS-120 SuperDisk boot is supported",
        "ATAPI ZIP drive boot is supported", "1394 boot is supported",
        "Smart battery is supported", "BIOS Boot Specification is supported",
        "Function key-initiated network service boot is supported",
        "Enabled targeted content distribution",
        "UEFI Specification is supported",
        "SMBIOS table describes a virtual machine",
        "Reserved for future assignment"
};


DWORD Find_EPS_Addr(EPS *eps, BYTE *addr);
WORD Find_Structure(BYTE *TableAddress, WORD StructureCount, BYTE Type);

int main()
{
        char ch ;
        while(1)
        {
                printf("\n");
                printf("***************************************************\n");
                printf("* 1.show entries of type 0                        *\n");
                printf("* 2.exit                                          *\n");
                printf("***************************************************\n");
                printf("PLEASE ENTER YOUR CHOICE : ");
                scanf("%d",&ch);
                while(getchar()!='\n')
                        continue;
                switch(ch)
                {
                        case 1:dmidecode();
                        break;
                        case 2:exit(0);
                        break;
                        default:printf("INVALID COMMAND!--NOT EXISTS \n");
                        break;
                }
        }
        return 0;
}



DWORD Find_EPS_Addr(EPS *eps, BYTE *addr)
{
        DWORD i;
        BYTE * SM;
       
        SM = addr;
        for(i = 0; i <= 0xFFFF; i++)
        {
               
                if(SM == MAP_FAILED)
                {
                        handle_error("mmap");
                }
                if(SM[i] != '_' || SM[i+1] != 'S' || SM[i+2] != 'M' || SM[i+3] != '_')
                        continue;
               
                if(SM[i+16] != '_' || SM[i+17] != 'D' || SM[i+18] != 'M' || SM[i+19] != 'I'|| SM[i+20] != '_')
                        continue;
               
                eps->Length = *(short *)(SM + i + 0x16);
                eps->Address = *(DWORD *)(SM + i + 0x18);
                eps->Struct_Count = *(short *)(SM + i + 0x1C);
                eps->Major_Version = *(short *)(SM + i + 0x06);
                eps->Minor_Version = *(short *)(SM + i + 0x07);
        }
       
       
        return 0;
}


int dmidecode()
{       
        DWORD Table_Address,segment,offset;
        EPS p = {0, 0, 0, 0, 0};
        EPS *eps = &p;
        int fd = open("/dev/mem",O_RDONLY|O_SYNC);
        if(fd == -1)
        {
                handle_error("open /dev/mem");
                return -1;
        }
        //void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
        BYTE *addr= mmap(0, EndAddress-StartAddress, PROT_READ, MAP_SHARED, fd, 0xF0000);
       
        Find_EPS_Addr(eps, addr);

        printf("SMBIOS %d.%d present.\n", eps->Major_Version, eps->Minor_Version);
        if(eps->Major_Version >= 3)
                {
                        printf("# SMBIOS implementations newer than version 3.0 are not\n");
                        printf("# fully supported by this version of dmidecode.\n");
                }
        printf("%d structures occupying %d bytes.\nTable at 0x%08X.\n", eps->Struct_Count, eps->Length, eps->Address);
       
       
        Table_Address = eps->Address;
        segment = Table_Address & 0xFFFF;
        offset = Table_Address & 0xF0000;
       
        BYTE * TableAddress = (BYTE *)mmap(0, segment + eps->Length , PROT_READ, MAP_SHARED, fd, offset);
       
        Find_Structure((TableAddress + segment), eps->Struct_Count, 0);
       

        //usage of munmap
        //int munmap(void *addr, size_t length);
        munmap(addr, 0xFFFF);
        munmap(TableAddress, 0xFFFF);
        return 0;
}


//Find specified type0 's structure
//TableAddress value is located at offset 18h in EPS table
//StructureCount value is located at offset 1Ch in EPS

WORD Find_Structure(BYTE *TableAddress, WORD StructureCount, BYTE Type)
{
        int i;
        char *str[10];
        BYTE currtype;
        BYTE *Addr;
        BYTE *firstAddr = TableAddress;
       
        while(TableAddress-firstAddr <  StructureCount)
        {
                               
                currtype = ((Header *)TableAddress)->Type;
               
                if(currtype != 0)
                {
                        TableAddress += ((Header *)TableAddress)->Length;
                        while(*(WORD *)TableAddress != 0)
                        {
                                TableAddress ++;
                        }
                        TableAddress += 2;
                }
                else
                {
                        Addr = TableAddress;
                        TableAddress += ((Header *)Addr)->Length;
                        while(*(WORD *)TableAddress != 0 && *(WORD *)(TableAddress -1) !=0)
                        {
                               
                                str[i+1] = (char *)TableAddress;
                               
                                while(*(BYTE *)TableAddress != 0)
                                {
                                        TableAddress ++;
                                }
                                i ++;
                                TableAddress ++;
                               
                        }       
                }
        }

        BYTE type = Addr[0x00];
        BYTE length = Addr[0x01];
        WORD handle = Addr[0x02];
        printf("\nHandle 0x%04x, DMI type %d, %d bytes\n",handle,type,length);
        printf("BIOS Information\n");
       
        //vendor
        printf("%15s %s\n","Vendor:", Addr[0x04]==0x0000 ? "": str[Addr[0x04]]);
       
        //version
        printf("%16s %s\n","Version:", Addr[0x05]==0x0000 ? "": str[Addr[0x05]]);
       
        //address
        WORD Address = *(WORD *)(Addr+6);
        printf("%16s 0x%X\n","Address:", StartAddress);
       
        //release date
        printf("%21s %s\n","Release Date:", Addr[0x08]==0x0000 ? "": str[Addr[0x08]]);
       
        //Runtime Size
        printf("%21s %d %s\n","Runtime Size:", (0x10000-Address) * 16 /1024, "KB");
       
        //ROM Size
        printf("%17s %d %s\n","ROM Size:", (Addr[0x09]+1) * 64, "KB");
       
        //BIOS Characteristics
        printf("%24s\n","Characteristics:");
        QWORD CHAR = *(QWORD *)(Addr + 0x0A);
        WORD CHAR_ex = *(WORD *)(Addr + 0x12);
               
        //printf("%x\n",CHAR);
        //0011_0111_1000_1011_1001_1000_1000_0000b
        for(i = 0; i < 32; i++)
        {
                if((CHAR >> i) & 1)//check if each bit equals to 1
                {
                        printf("%16s%s\n","",characteristics[i]);
                }       
        }
       
        for(i = 0; i < 13; i++)
        {
               
                if((CHAR_ex >> i) & 1)
                {
                        printf("%16s%s\n","",characteristics_ex[i]);
                }
        }
       
        //BIOS Revision
        //if the system does not support the use of this field ,the value is 0FFh
        if(Addr[0x14] != 0xFF || Addr[0x15] != 0xFF)
                {
                        printf("%22s %d.%d\n","BIOS Revision:",Addr[0x14],Addr[0x15]);
                }
       
        //Firmware Revision
        //if the system does not have field upgradeable embedded controller firmware ,the value is 0FFh
        if(Addr[0x16] != 0xFF || Addr[0x17] != 0xFF)
                {
                        printf("%26s %d.%d\n","Firmware Revision:",Addr[0x16],Addr[0x17]);
                }

        return 0;
       
}





       
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-10-10 16:24:40 | 显示全部楼层
有人可以根据这个帮忙改一版代码吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-10 18:02:03 | 显示全部楼层
是这个吗?
https://blog.csdn.net/zhoudaxia/article/details/5919699
那么看到下面这张图,你是不是就会写代码了?
1.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-10 18:11:16 | 显示全部楼层
1.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-10 18:11:49 | 显示全部楼层    本楼为最佳答案   
#include <stdio.h>
#include <stdlib.h>

#define __USE_GNU
#include <string.h>

#include <errno.h>

int main(void) {
    FILE *fp = fopen("/dev/mem", "r");
    if(!fp) {
        int err = errno;
        perror("/dev/mem");
        exit(-err);
    }
    fseek(fp, 0xf0000, SEEK_SET);
    char buff[65536];
    fread(buff, 1, 65536, fp);
    char *eps = memmem(buff, 65536, "_SM_", 4);
    if(eps && !strncmp(eps + 16, "_DMI_", 5)) {
        eps = (char *)(eps - buff + 0xf0000);
        printf("%p\n", eps);
    }
    fclose(fp);
    return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-10-10 19:07:12 | 显示全部楼层

谢谢大佬,请问这个程序是实现了什么功能呢?我希望的是可以完成遍历SMBIOS信息
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-10 19:13:58 | 显示全部楼层
2wsx 发表于 2022-10-10 19:07
谢谢大佬,请问这个程序是实现了什么功能呢?我希望的是可以完成遍历SMBIOS信息

这篇文章你看了吗?
https://blog.csdn.net/zhoudaxia/article/details/5919699
     对于非 EFI 的系统,访问 SMBIOS EPS 表的操作过程如下:

     1 .从物理内存 0x000F0000-0x000FFFFF 之间寻找关键字 “ _SM_” 。

     2 .找到后再向后 16 个字节,看后面 5 个 BYTE 是否是关键字 “_DMI_” ,如果是, EPS 表即找到。

     对于 UEFI (是 BIOS 的下一代版本)系统,可能通过搜索 EFI 配置表中的 SMBIOS GUID(SMBIOS_TABLE_GUID) ,然后使用指向 SMBIOS 的指针来定位 EPS 表。具体可参考 UEFI 规范。 

上面的代码定位eps表在内存中的位置

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-15 11:20:54 | 显示全部楼层
本帖最后由 howzyao 于 2022-10-15 11:24 编辑


fseek(fp, 0xf0000, SEEK_SET);

中的 0xf0000 可以理解成1个0代表2进制的8个位吗? 共4*8=32个位,分成4段,每段8个位.谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-10-15 11:52:33 | 显示全部楼层
howzyao 发表于 2022-10-15 11:20
fseek(fp, 0xf0000, SEEK_SET);

中的 0xf0000 可以理解成1个0代表2进制的8个位吗? 共4*8=32个位,分 ...

一个0是4个bit
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-28 18:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表