// irqs.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include <assert.h>
MapViewOfSection NtMapViewOfSection;
UnmapViewOfSection NtUnmapViewOfSection;
OpenSection NtOpenSection;
Close NtClose;
USHORT selector;
HANDLE event;
void kernelfunction(DWORD usercs,DWORD irq)
{
DWORD absent =0; BYTE gdtr[8];
//check if ioapic is present and enabled
if(irq<=23)
{
_asm
{
mov eax,1 ;
cpuid ;
and edx, 0x00000200 ;
cmp edx,0 ;
jne skip1 ;
mov absent,1 ;
skip1:
mov ecx,0x1b ;
rdmsr ;
and eax,0x00000800 ;
cmp eax,0 ;
jne skip2 ;
mov absent,1 ;
}
//if APIC is enabled, get vector from it and return
skip2:
if(!absent)
{
//map ioapic - make sure that we map it to non-cached memory. Certainly,we have to do it only
//upon the function's very first invocation, i.e. when irq is 0
if(!irq)
{
_asm
{
mov ebx,0xfec00000 ;
or ebx,0x13 ;
mov eax,0xc0000000 ;
mov dword ptr[eax],ebx ;
}
}
//now we are about to get interrupt vector
PULONG array=NULL;
//write 0x10+2*irq to IOREGSEL
array[0]=0x10+2*irq;
// subsequent read from IOWIN returns 32 low-order bits of Redirection Table that corresponds to our IRQ.
// 8 low-order bits are interrupt vector, corresponding to our IRQ
DWORD vector=(array[4]&0xff);
// return interrupt vector. Dont forget that we must return with RETF, and pop 4 bytes
// off the stack
_asm
{
mov eax,vector ;
mov esp,ebp ;
pop ebp ;
retf 4 ;
}
}
}
//either apic is not supported, or irq is above 23,i.e. this is the last invocation
//therefore, clean up gdt and return 500 -the caller knows how to interpret it this value
_asm
{
//clean up gdt
sgdt gdtr ;
lea eax,gdtr ;
mov ebx,dword ptr[eax+2] ;
mov eax,0 ;
mov ax,selector ;
shl eax,3 ;
add ebx,eax ;
mov dword ptr[ebx],0 ;
mov dword ptr[ebx+4],0 ;
// adjust stack and return
mov eax,500 ;
mov esp,ebp ;
pop ebp ;
retf 4 ;
}
}
void go()
{
EXPLICIT_ACCESS Access;
PACL OldDacl=NULL, NewDacl=NULL;
PVOID security;
HANDLE Section;
NTSTATUS status;
INIT_UNICODE_STRING(name, L"\\Device\\PhysicalMemory");
OBJECT_ATTRIBUTES oa ={sizeof(oa),0,&name,0,0,0};
memset(&Access, 0, sizeof(EXPLICIT_ACCESS));
NtOpenSection(&Section, WRITE_DAC | READ_CONTROL, &oa);
GetSecurityInfo(Section, SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION, NULL, NULL, &OldDacl,
NULL, &security);
Access.grfAccessPermissions = SECTION_ALL_ACCESS;
Access.grfAccessMode = GRANT_ACCESS;
Access.grfInheritance = NO_INHERITANCE;
Access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
Access.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
Access.Trustee.TrusteeType = TRUSTEE_IS_USER;
Access.Trustee.ptstrName = "CURRENT_USER";
// update ACL
SetEntriesInAcl(1, &Access, OldDacl, &NewDacl);
SetSecurityInfo(Section, SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION, NULL, NULL, NewDacl,
NULL);
CloseHandle(Section);
//check how much RAM we've got
MEMORYSTATUS meminfo;
GlobalMemoryStatus(&meminfo);
//get handle to RAM
status = NtOpenSection(&Section,SECTION_MAP_READ|SECTION_MAP_WRITE,&oa);
DWORD found=0,MappedSize,x;
LARGE_INTEGER phys;
DWORD* entry,*pteEntry;
PVOID DirectoryMappedAddress,TableMappedAddress;
DWORD DirectoryOffset,TableOffset;
for(x=0;x<meminfo.dwTotalPhys;x+=0x1000)
{
//map current page in RAM
MappedSize=4096;
phys.QuadPart=x;
DirectoryMappedAddress=0;
status = NtMapViewOfSection(Section, (HANDLE) -1, &DirectoryMappedAddress, 0L,MappedSize, &phys, &MappedSize, ViewShare,0, PAGE_READONLY);
if(status)
continue;
entry=(DWORD*)DirectoryMappedAddress;
//get offsets
DirectoryOffset=(DWORD)DirectoryMappedAddress;
TableOffset=(DWORD)DirectoryMappedAddress;
DirectoryOffset>>=22;
TableOffset=(TableOffset>>12)&0x3ff;
if((entry[0x301]&1)!=1 || (entry[DirectoryOffset]&1)!=1)
{
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
continue;
}
MappedSize=4096;
phys.QuadPart=(entry[0x301]&0xfffff000);
TableMappedAddress=0;
status = NtMapViewOfSection(Section, (HANDLE) -1, &TableMappedAddress, 0L,MappedSize, &phys, &MappedSize, ViewShare,0, PAGE_READONLY);
if(status)
{
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
continue;
}
pteEntry = (DWORD*)TableMappedAddress;
if((pteEntry[0x200]&0xfffff000)!=x || (pteEntry[0x200]&1)!=1)
{
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
NtUnmapViewOfSection((HANDLE) -1, TableMappedAddress);
continue;
}
NtUnmapViewOfSection((HANDLE) -1, TableMappedAddress);
MappedSize=4096;
phys.QuadPart=(entry[DirectoryOffset]&0xfffff000);
TableMappedAddress=0;
status = NtMapViewOfSection(Section, (HANDLE) -1, &TableMappedAddress, 0L,MappedSize, &phys, &MappedSize, ViewShare,0, PAGE_READONLY);
if(status)
{
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
continue;
}
//now let's check if this is really a page table If yes, 20 upper bits of (V>>12)&0x3ff-th
//entry must be equal to P, and Present bit must be set in this entry. If the above is true,
// P is really a page directory
entry=(DWORD*)TableMappedAddress;
if((entry[TableOffset]&1)==1 && (entry[TableOffset]&0xfffff000)==x)
found++;
NtUnmapViewOfSection((HANDLE) -1, TableMappedAddress);
//directory is found - no need to proceed further
if(found)
break;
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
}
assert(found != 0);
//get base address of gdt
BYTE gdtr[8];
DWORD gdtbase,physgdtbase;
_asm
{
sgdt gdtr ;
lea eax,gdtr ;
mov ebx,dword ptr[eax+2] ;
mov gdtbase,ebx ;
}
//get directory and table offsets
DirectoryOffset=gdtbase;TableOffset=gdtbase;
DirectoryOffset>>=22;TableOffset=(TableOffset>>12)&0x3ff;
entry=(DWORD*)DirectoryMappedAddress;
//map page table - phys. address of it is 20 upper bits of (V-22)-th entry of page directory
MappedSize=4096; phys.QuadPart=(entry[DirectoryOffset]&0xfffff000); TableMappedAddress=0;
status = NtMapViewOfSection(Section, (HANDLE) -1, &TableMappedAddress, 0L,MappedSize, &phys, &MappedSize, ViewShare,0, PAGE_READONLY);
//phys page is in 20 upper bits of (V>>12)&0x3ff-th entry of page table- this is what we need
entry=(DWORD*)TableMappedAddress;
physgdtbase=(entry[TableOffset]&0xfffff000);
//unmap everything
NtUnmapViewOfSection((HANDLE) -1, TableMappedAddress);
NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);
//now let's map gdt
PBYTE GdtMappedAddress=0;phys.QuadPart=physgdtbase;MappedSize=4096;
NtMapViewOfSection(Section, (HANDLE) -1, (PVOID*)&GdtMappedAddress, 0L,MappedSize, &phys, &MappedSize, ViewShare,0, PAGE_READWRITE);
gdtbase&=0xfff;
GdtMappedAddress+=gdtbase;
CallGateDescriptor * gate=(CallGateDescriptor * )GdtMappedAddress;
//now let's find free entry in GDT. Type of current gdt entry does not matter - Present
// bit is 48-th bit for all type of descriptors, so we interpret all descriptors as call gates
selector=1;
while(1)
{
if(!gate[selector].present)break;
selector++;
}
// now let's set up a call gate
gate[selector].offset_low = (WORD) ((DWORD)kernelfunction & 0xFFFF);
gate[selector].selector = 8;
gate[selector].param_count = 1; //we will pass a parameter
gate[selector].unused = 0;
gate[selector].type = 0xc; // 32-bit callgate
gate[selector].dpl = 3; // must be 3
gate[selector].present = 1;
gate[selector].offset_high = (WORD) ((DWORD)kernelfunction >> 16);
//we don't need physical memory any more
NtUnmapViewOfSection((HANDLE) -1, GdtMappedAddress);
CloseHandle(Section);
// now we will get interrupt vectors
DWORD res;
DWORD resultarray[24];
ZeroMemory(resultarray,sizeof(resultarray));
for (x=0;x<25;x++)
{
//let's call the function via the call gate. Are you ready???
WORD farcall[3];
farcall[2] = (selector<<3);
_asm
{
mov ebx,x ;
push ebx ;
call fword ptr [farcall] ;
mov res,eax ;
}
if(x==24)
break;
//if the return value is 500 and this was not the final invocation, apic is not present
//inform the user about it, and that't it - it does not make sense to proceed with the loop
if(res==500)
{
MessageBox(GetDesktopWindow()," APIC is not supported","IRQs",MB_OK);
break;
}
resultarray[x]=res;
}
// inform the user
for (x=0;x<24;x++)
{
res=resultarray[x];
//if irq is not present, the return value is 0xFF, so proceed to the next entry
// if apic is not ebabled, the whole array is still filled with zeroes
if(res==0xff || res==0)
continue;
// inform the user about mapping of current IRQ
char numbuff[8];
char buff[64];
strcpy(buff,"IRQ");
sprintf(numbuff,"%d\n",x);
strcat(buff,numbuff);
DWORD a=strlen(buff);
buff[a-1]='\0';
strcat(buff," maps to vector ");
sprintf(numbuff,"%X\n",res);
strcat(buff,numbuff);
a=strlen(buff);
buff[a-1]='\0';
MessageBox(GetDesktopWindow(),buff,"IRQs",MB_OK);
}
SetEvent(event);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
NtMapViewOfSection=(MapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtMapViewOfSection");
NtUnmapViewOfSection=(UnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtUnmapViewOfSection");
NtOpenSection=(OpenSection)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtOpenSection");
NtClose=(Close)GetProcAddress(GetModuleHandle("ntdll.dll"),"NtClose");
event=CreateEvent(0,0,0,"event");
DWORD dw;
HANDLE thread=CreateThread(0,0,(LPTHREAD_START_ROUTINE)go,0,CREATE_SUSPENDED,&dw);
SetThreadAffinityMask (thread,1);
ResumeThread(thread);
WaitForSingleObject(event,INFINITE);
// TODO: Place code here.
return 0;
}