1.linux设备驱动程序——设备树(0)-dtb格式
2.VB如何获取硬件信息比如CPU温度,显卡,CPUID号之类的、
3.VC++ MFCå¦ä½è·åCPU IDå硬ççåºåå·ï¼
linux设备驱动程序——设备树(0)-dtb格式
设备树的一般操作方式是:开发人员根据开发需求编写dts文件,然后使用dtc将dts编译成dtb文件。
dts文件是c语言源码包文本格式的文件,而dtb是二进制文件,在linux启动时被加载到内存中,接下来我们需要来分析设备树dtb文件的格式。
为什么要了解设备树dtb文件的格式
dtb作为二进制文件被加载到内存中,然后由内核读取并进行解析,如果对dtb文件的格式不了解,那么在看设备树解析相关的内核代码时将会寸步难行,而阅读源代码才是了解设备树最好的方式,所以,asp 源码封装如果需要更透彻的了解设备树解析的细节,第一步就是需要了解设备树的格式。
dtb格式总览
dtb的格式是这样的:
dtb header
但凡涉及到数据的记录,就一定会有一个总的描述部分,就像磁盘的超级块,书的目录,dtb当然也不例外,这个描述头部就是dtb的header部分,通过这个header部分,用户可以快速地了解到整个dtb的大致信息。
header可以用这么一个结构体来描述:
magic
设备树的魔数,魔数其实就是一个用于识别的数字,表示设备树的开始,linux dtb的liteos分析源码魔数为 0xddfeed.
totalsize
这个设备树的size,也可以理解为所占用的实际内存空间。
off_dt_struct
offset to dt_struct,表示整个dtb中structure部分所在内存相对头部的偏移地址
off_dt_strings
offset to dt_string,表示整个dtb中string部分所在内存相对头部的偏移地址
off_mem_rsvmap
offset to memory reserve map,dtb中memory reserve map所在内存相对头部的偏移地址,
version
设备树的版本,截至目前的最新版本为.
last_comp_version
最新的兼容版本
boot_cpuid_phys
这部分仅在版本2中存在,后续版本不再使用。
size_dt_strings
表示整个dtb中string部分的大小
size_dt_struct
表示整个dtb中struct部分的大小
alignment gap
中间的alignment gap部分表示对齐间隙,它并非是必须的,它是否被提供以及大小由具体的平台对数据对齐和的要求以及数据是否已经对齐来决定。
memory reserve map
memory reserve map:描述保留的内存部分,这个map的数据结构是这样的:
这部分存储了此结构的列表,整个部分的vc源码代码结尾由一个数据为0的结构来表示(即physical_address和size都为0,总共字节)。
这一部分的数据并非是节点中的memory子节点,而是在设备开始之前(也就是第一个花括号之前)定义的,例如:
这一部分的作用是告诉内核哪一些内存空间需要被保留而不应该被系统覆盖使用,因为在内核启动时常常需要动态申请大量的内存空间,只有提前进行注册,用户需要使用的内存才不会被系统征用而造成数据覆盖。
值得一提的是,对于设备树而言,即使不指定保留内存,系统也会默认为设备树保留相应的内存空间。
同时,这一部分需要位(8字节)对齐。
device-tree structure
device-tree structure:每个节点都会被描述为一个struct,节点之间可以嵌套,loud源码解析因此也会有嵌套的struct。
structure的的结构是这样的:
device-tree strings
device-tree strings:在dtb中有大量的重复字符串,比如"model","compatile"等等,为了节省空间,将这些字符串统一放在某个地址,需要使用的时候直接使用索引来查看。
需要注意的是,属性部分格式为key = value,key部分被放置在strings部分,而value部分的字符串并不会放在这一部分,而是直接放在structure中。
dtb文件解析示例
光说不练假把式,下面我就使用一个简单的示例来剖析dtb的文件格式。
下述示例仅仅是一个演示demo,不针对任何平台,为了演示方便,编写了一个非常简单的dts文件。 /dts-v1/; / {
编译当前dts文件,获取对应的dtb文件。
鉴于dtb文件为二进制文件,普通编辑器打开显示乱码,我们使用ultraEdit查看,它将数据以进制形式显示:
整个dtb文件还是比较简单的,图中的红色框出的部分为header部分的数据,可以看到:
整个头部为字节,进制为0x,从头部信息中off_mem_rsvmap部分可以得到,reserve memory起始地址为0x,上文中提到,这一部分使用一个字节的struct来描述,以一个全为0的struct结尾。
后字节全为0,可以看出,这里并没有设置reserve memory。
structure 部分
上文回顾:每一个属性都是以 key = value的形式来描述,value部分可选。
偏移地址来到0x(0x+0x),接下来8个字节为,根据上述structure中的描述,这是OF_DT_PROP,即标示属性的开始。
接下来4字节为,表明该属性的value部分size为字节。
接下来4字节是当前属性的key在string 部分的偏移地址,这里是,由头部信息中off_dt_strings可以得到,string部分的开始为,偏移地址为0,所以对应字符串为"compatible".
之后就是value部分,这部分的数据是字符串,可以直接从右侧栏看出,总共字节的字符串"hd,test_dts", "hd,test_xxx",因为字符串之间以0结尾,所以程序可以识别出这是两个字符串。
可以看出,到这里,compatible = "hd,test_dts", "hd,test_xxx";这个属性就被描述完了,对于属性的描述还是非常简单的。
按照固有的规律,接下来就是对#address-cells = <0x1>的解析,然后是#size-cells = <0x1>...
然后就是递归的子节点chosen,memory@等等都是按照上文中提到的structure解析规则来进行解析,最后以结尾。
与根节点不同的是,子节点有一个unit name,即chosen,memory@这些名称,并非节点中的.name属性。
而整个结构的结束由来描述。
一般而言,在位系统中,dtc在编译dts文件时会自动考虑对齐问题,所以对于设备树的对齐字节,我们只需要有所了解即可,并不会常接触到。
好了,关于linux设备树dtb文件格式的讨论就到此为止啦。
VB如何获取硬件信息比如CPU温度,显卡,CPUID号之类的、
Dim MemoyCounter As New ComputerInfo()
Dim CPUCounter As New PerformanceCounter("Processor", "% Processor Time", "_Total")
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim CPU As Double = CPUCounter.NextValue
Dim neicun As Double = (MemoyCounter.TotalPhysicalMemory - MemoyCounter.AvailablePhysicalMemory) / MemoyCounter.TotalPhysicalMemory * %
获取CPU及物理内存使用率
VC++ MFCå¦ä½è·åCPU IDå硬ççåºåå·ï¼
// âè·å¾Intel CPU IDâæé®æ¶æ¯å¤çå½æ°
void CIntelCPUIDDlg::OnBtnCPUID()
{
unsigned long s1,s2;
unsigned char vendor_id[]="------------";//CPUæä¾åID
CString str1,str2,str3;
// 以ä¸ä¸ºè·å¾CPU IDçæ±ç¼è¯è¨æ令
_asm // å¾å°CPUæä¾åä¿¡æ¯
{
xor eax,eax // å°eaxæ¸ 0
cpuid // è·åCPUIDçæ令
mov dword ptr vendor_id,ebx
mov dword ptr vendor_id[+4],edx
mov dword ptr vendor_id[+8],ecx
}
str1.Format("%s",vendor_id);
_asm // å¾å°CPU IDçé«ä½
{
mov eax,h
xor edx,edx
cpuid
mov s2,eax
}
str2.Format("%X-",s2);
_asm // å¾å°CPU IDçä½ä½
{
mov eax,h
xor ecx,ecx
xor edx,edx
cpuid
mov s1,edx
mov s2,ecx
}
str3.Format("%X-%X\n",s1,s2);
str2=str2+str3;
m_editVendor.SetWindowText(str1);
m_editCPUID.SetWindowText(str2);
}
// GetHDSerial.cpp: implementation of the CGetHDSerial class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "GetHDSerial.h"
char m_buffer[];
WORD m_serial[];
DWORD m_OldInterruptAddress;
DWORDLONG m_IDTR;
// çå¾ ç¡¬ç空é²
static unsigned int WaitHardDiskIdle()
{
BYTE byTemp;
Waiting:
_asm
{
mov dx, 0x1f7
in al, dx
cmp al, 0x
jb Endwaiting
jmp Waiting
}
Endwaiting:
_asm
{
mov byTemp, al
}
return byTemp;
}
//ä¸ææå¡ç¨åº
void _declspec( naked )InterruptProcess(void)
{
int byTemp;
int i;
WORD temp;
//ä¿åå¯åå¨å¼
_asm
{
push eax
push ebx
push ecx
push edx
push esi
}
WaitHardDiskIdle();//çå¾ ç¡¬ç空é²ç¶æ
_asm
{
mov dx, 0x1f6
mov al, 0xa0
out dx, al
}
byTemp = WaitHardDiskIdle(); //è¥ç´æ¥å¨Ring3级æ§è¡çå¾ å½ä»¤ï¼ä¼è¿å ¥æ»å¾ªç¯
if ((byTemp&0x)!=0x)
{
_asm // æ¢å¤ä¸æç°åºå¹¶éåºä¸ææå¡ç¨åº
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
_asm
{
mov dx, 0x1f6 //å½ä»¤ç«¯å£1f6,éæ©é©±å¨å¨0
mov al, 0xa0
out dx, al
inc dx
mov al, 0xec
out dx, al //åé读驱å¨å¨åæ°å½ä»¤
}
byTemp = WaitHardDiskIdle();
if ((byTemp&0x)!=0x)
{
_asm // æ¢å¤ä¸æç°åºå¹¶éåºä¸ææå¡ç¨åº
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
//读å硬çæ§å¶å¨çå ¨é¨ä¿¡æ¯
for (i=0;i<;i++)
{
_asm
{
mov dx, 0x1f0
in ax, dx
mov temp, ax
}
m_serial[i] = temp;
}
_asm
{
pop esi
pop edx
pop ecx
pop ebx
pop eax
iretd
}
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGetHDSerial::CGetHDSerial()
{
}
CGetHDSerial::~CGetHDSerial()
{
}
// 读å硬çåºåå·å½æ°
char* CGetHDSerial::GetHDSerial()
{
m_buffer[0]='\n';
// å¾å°å½åæä½ç³»ç»çæ¬
OSVERSIONINFO OSVersionInfo;
OSVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx( &OSVersionInfo);
if (OSVersionInfo.dwPlatformId != VER_PLATFORM_WIN_NT)
{
// Windows 9x/MEä¸è¯»å硬çåºåå·
WORD m_wWin9xHDSerial[];
Win9xReadHDSerial(m_wWin9xHDSerial);
strcpy (m_buffer, WORDToChar (m_wWin9xHDSerial, , ));
}
else
{
// Windows NT//XPä¸è¯»å硬çåºåå·
DWORD m_wWinNTHDSerial[];
// å¤ææ¯å¦æSCSI硬ç
if ( ! WinNTReadIDEHDSerial(m_wWinNTHDSerial))
WinNTReadSCSIHDSerial(m_wWinNTHDSerial);
strcpy (m_buffer, DWORDToChar (m_wWinNTHDSerial, , ));
}
return m_buffer;
}
// Windows9X/MEç³»ç»ä¸è¯»å硬çåºåå·
void _stdcall CGetHDSerial::Win9xReadHDSerial(WORD * buffer)
{
int i;
for(i=0;i<;i++)
buffer[i]=0;
_asm
{
push eax
//è·åä¿®æ¹çä¸æçä¸ææ述符ï¼ä¸æé¨ï¼å°å
sidt m_IDTR
mov eax,dword ptr [m_IDTR+h]
add eax,3*h+h
cli
//ä¿ååå çä¸æå ¥å£å°å
push ecx
mov ecx,dword ptr [eax]
mov cx,word ptr [eax-h]
mov dword ptr m_OldInterruptAddress,ecx
pop ecx
//设置修æ¹çä¸æå ¥å£å°å为æ°çä¸æå¤çç¨åºå ¥å£å°å
push ebx
lea ebx,InterruptProcess
mov word ptr [eax-h],bx
shr ebx,h
mov word ptr [eax+h],bx
pop ebx
//æ§è¡ä¸æï¼è½¬å°Ring 0ï¼ç±»ä¼¼CIHç æ¯åçï¼
int 3h
//æ¢å¤åå çä¸æå ¥å£å°å
push ecx
mov ecx,dword ptr m_OldInterruptAddress
mov word ptr [eax-h],cx
shr ecx,h
mov word ptr [eax+h],cx
pop ecx
sti
pop eax
}
for(i=0;i<;i++)
buffer[i]=m_serial[i];
}
// Windows 9x/MEç³»ç»ä¸ï¼å°åç±»åï¼WORDï¼ç硬çä¿¡æ¯è½¬æ¢ä¸ºå符类åï¼charï¼
char * CGetHDSerial::WORDToChar (WORD diskdata [], int firstIndex, int lastIndex)
{
static char string [];
int index = 0;
int position = 0;
// æç §é«åèå¨åï¼ä½åèå¨åç顺åºå°åæ°ç»diskdata ä¸å 容åå ¥å°å符串stringä¸
for (index = firstIndex; index <= lastIndex; index++)
{
// åå ¥åä¸çé«åè
string [position] = (char) (diskdata [index] / );
position++;
// åå ¥åä¸çä½åè
string [position] = (char) (diskdata [index] % );
position++;
}
// æ·»å å符串ç»ææ å¿
string [position] = '\0';
// å é¤å符串ä¸ç©ºæ ¼
for (index = position - 1; index > 0 && ' ' == string [index]; index--)
string [index] = '\0';
return string;
}
// Windows NT//XPç³»ç»ä¸ï¼å°ååç±»åï¼DWORDï¼ç硬çä¿¡æ¯è½¬æ¢ä¸ºå符类åï¼charï¼
char* CGetHDSerial::DWORDToChar (DWORD diskdata [], int firstIndex, int lastIndex)
{
static char string [];
int index = 0;
int position = 0;
// æç §é«åèå¨åï¼ä½åèå¨åç顺åºå°ååä¸çä½ååå ¥å°å符串stringä¸
for (index = firstIndex; index <= lastIndex; index++)
{
// åå ¥ä½åä¸çé«åè
string [position] = (char) (diskdata [index] / );
position++;
// åå ¥ä½åä¸çä½åè
string [position] = (char) (diskdata [index] % );
position++;
}
// æ·»å å符串ç»ææ å¿
string [position] = '\0';
// å é¤å符串ä¸ç©ºæ ¼
for (index = position - 1; index > 0 && ' ' == string [index]; index--)
string [index] = '\0';
return string;
}
// Windows NT//XPä¸è¯»åIDE硬çåºåå·
BOOL CGetHDSerial::WinNTReadIDEHDSerial(DWORD * buffer)
{
BYTE IdOutCmd [sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1];
BOOL bFlag = FALSE;
int drive = 0;
char driveName [];
HANDLE hPhysicalDriveIOCTL = 0;
sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);
// Windows NT//XPä¸å建æ件éè¦ç®¡çåæé
hPhysicalDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
{
GETVERSIONOUTPARAMS VersionParams;
DWORD cbBytesReturned = 0;
// å¾å°é©±å¨å¨çIOæ§å¶å¨çæ¬
memset ((void*) &VersionParams, 0, sizeof(VersionParams));
if(DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_VERSION,
NULL, 0, &VersionParams,
sizeof(VersionParams),
&cbBytesReturned, NULL) )
{
if (VersionParams.bIDEDeviceMap > 0)
{
BYTE bIDCmd = 0; // IDEæè ATAPIè¯å«å½ä»¤
SENDCMDINPARAMS scip;
// å¦æ驱å¨å¨æ¯å 驱ï¼éç¨å½ä»¤IDE_ATAPI_IDENTIFYï¼ command,
// å¦åéç¨å½ä»¤IDE_ATA_IDENTIFY读å驱å¨å¨ä¿¡æ¯
bIDCmd = (VersionParams.bIDEDeviceMap >> drive & 0x)?
IDE_ATAPI_IDENTIFY : IDE_ATA_IDENTIFY;
memset (&scip, 0, sizeof(scip));
memset (IdOutCmd, 0, sizeof(IdOutCmd));
// è·å驱å¨å¨ä¿¡æ¯
if (WinNTGetIDEHDInfo (hPhysicalDriveIOCTL,
&scip,
(PSENDCMDOUTPARAMS)&IdOutCmd,
(BYTE) bIDCmd,
(BYTE) drive,
&cbBytesReturned))
{
int m = 0;
USHORT *pIdSector = (USHORT *)
((PSENDCMDOUTPARAMS) IdOutCmd) -> bBuffer;
for (m = 0; m < ; m++)
buffer[m] = pIdSector [m];
bFlag = TRUE; // 读å硬çä¿¡æ¯æå
}
}
}
CloseHandle (hPhysicalDriveIOCTL); // å ³éå¥æ
}
return bFlag;
}
// WindowsNT//XPç³»ç»ä¸è¯»åSCSI硬çåºåå·
BOOL CGetHDSerial::WinNTReadSCSIHDSerial (DWORD * buffer)
{
buffer[0]='\n';
int controller = 0;
HANDLE hScsiDriveIOCTL = 0;
char driveName [];
sprintf (driveName, "\\\\.\\Scsi%d:", controller);
// Windows NT//XPä¸ä»»ä½æéé½å¯ä»¥è¿è¡
hScsiDriveIOCTL = CreateFile (driveName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (hScsiDriveIOCTL != INVALID_HANDLE_VALUE)
{
int drive = 0;
DWORD dummy;
for (drive = 0; drive < 2; drive++)
{
char buffer [sizeof (SRB_IO_CONTROL) + SENDIDLENGTH];
SRB_IO_CONTROL *p = (SRB_IO_CONTROL *) buffer;
SENDCMDINPARAMS *pin =
(SENDCMDINPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
// åå¤åæ°
memset (buffer, 0, sizeof (buffer));
p -> HeaderLength = sizeof (SRB_IO_CONTROL);
p -> Timeout = ;
p -> Length = SENDIDLENGTH;
p -> ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
strncpy ((char *) p -> Signature, "SCSIDISK", 8);
pin -> irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pin -> bDriveNumber = drive;
// å¾å°SCSI硬çä¿¡æ¯
if (DeviceIoControl (hScsiDriveIOCTL, IOCTL_SCSI_MINIPORT,
buffer,
sizeof (SRB_IO_CONTROL) +
sizeof (SENDCMDINPARAMS) - 1,
buffer,
sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
&dummy, NULL))
{
SENDCMDOUTPARAMS *pOut =
(SENDCMDOUTPARAMS *) (buffer + sizeof (SRB_IO_CONTROL));
IDSECTOR *pId = (IDSECTOR *) (pOut -> bBuffer);
if (pId -> sModelNumber [0])
{
int n = 0;
USHORT *pIdSector = (USHORT *) pId;
for (n = 0; n < ; n++)
buffer[n] =pIdSector [n];
return TRUE; // 读åæå
}
}
}
CloseHandle (hScsiDriveIOCTL); // å ³éå¥æ
}
return FALSE; // 读å失败
}
// Windows NT//XPä¸è¯»åIDE设å¤ä¿¡æ¯
BOOL CGetHDSerial::WinNTGetIDEHDInfo (HANDLE hPhysicalDriveIOCTL, PSENDCMDINPARAMS pSCIP,
PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum,
PDWORD lpcbBytesReturned)
{
// 为读å设å¤ä¿¡æ¯åå¤åæ°
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
pSCIP -> irDriveRegs.bFeaturesReg = 0;
pSCIP -> irDriveRegs.bSectorCountReg = 1;
pSCIP -> irDriveRegs.bSectorNumberReg = 1;
pSCIP -> irDriveRegs.bCylLowReg = 0;
pSCIP -> irDriveRegs.bCylHighReg = 0;
// 计ç®é©±å¨å¨ä½ç½®
pSCIP -> irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4);
// 设置读åå½ä»¤
pSCIP -> irDriveRegs.bCommandReg = bIDCmd;
pSCIP -> bDriveNumber = bDriveNum;
pSCIP -> cBufferSize = IDENTIFY_BUFFER_SIZE;
// 读å驱å¨å¨ä¿¡æ¯
return ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_GET_DRIVE_INFO,
(LPVOID) pSCIP,
sizeof(SENDCMDINPARAMS) - 1,
(LPVOID) pSCOP,
sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
lpcbBytesReturned, NULL) );
}