//let's check if this page can be a page directory - 20 upper bits of 0x300-th entry
//must be //equal to P, and Present bit must be set in 0x300-th and V>>22-th entries.
//If not,proceed to next page
if((entry[0x300]&0xfffff000)!=x ||(entry[0x300]&1)!=1 || (entry[DirectoryOffset]&1)!=1)
{NtUnmapViewOfSection((HANDLE) -1, DirectoryMappedAddress);continue;}
//seems to be OK for the time being. Now let's try to map a possible page table
MappedSize=4096; phys.QuadPart=(entry[DirectoryOffset]&0xfffff000); TableMappedAddress=0;
status = NtMapViewOfSection(Section, (HANDLE) -1, &TableMappedAddress, 0L,MappedSize,
&phys, &MappedSize, ViewShare,0, PAGE_READONLY);
//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++;
//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);
//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???
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
if(res==500)
{
MessageBox(GetDesktopWindow()," APIC is not supported","IRQs",MB_OK);
break;
}
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
//either apic is not supported, or irq is above 23,i.e. this is the last invocation
//therefore, clean up gdt and return 500
_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
}
}