Kernel/x86 - Evil hack to do validation of virtual memory
authorJohn Hodge <[email protected]>
Mon, 17 Mar 2014 05:40:15 +0000 (13:40 +0800)
committerJohn Hodge <[email protected]>
Mon, 17 Mar 2014 05:40:15 +0000 (13:40 +0800)
KernelLand/Kernel/arch/x86/validate_vmem.c [new file with mode: 0644]

diff --git a/KernelLand/Kernel/arch/x86/validate_vmem.c b/KernelLand/Kernel/arch/x86/validate_vmem.c
new file mode 100644 (file)
index 0000000..11d504a
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ */
+#include <acess.h>
+#include <mm_virt.h>
+#include "include/vmem_layout.h"
+#include <threads_int.h>
+#include <stdbool.h>
+
+extern Uint64  giPageCount;
+extern tProcess        *gAllProcesses;
+extern char    gKernelEnd[];
+
+// === PROTOTYPES ===
+void   Validate_VirtualMemoryUsage(void);
+void   Validate_VirtualMemoryUsage_PT(const Uint32 *PTable, const tProcess *Proc, int PDIndex, int *RefCounts);
+static bool    _should_skip_pde(const tProcess *Proc, int idx, Uint32 pde);
+static void    _ref_mem(int *RefCounts, Uint PageNum, const tProcess *Proc, void *addr);
+static void    _load_page(Uint32 *dst, tPAddr phys);
+
+// === CODE ===
+void Validate_VirtualMemoryUsage(void)
+{
+        int    *refcount = calloc(giPageCount, sizeof(int));
+       Uint32  *tmp_pd = malloc( PAGE_SIZE );
+       Uint32  *tmp_pt = malloc( PAGE_SIZE );
+       
+       // Pass #1 - Count PT references
+       for( tProcess *proc = gAllProcesses; proc; proc = proc->Next )
+       {
+               Uint    cr3 = proc->MemState.CR3;
+               _ref_mem(refcount, cr3/PAGE_SIZE, proc, 0);
+
+               _load_page(tmp_pd, cr3);
+               const Uint32    *pdir = tmp_pd;
+               for(int i = 0; i < 1024; i ++)
+               {
+                       if( _should_skip_pde(proc, i, pdir[i]) )
+                               continue ;
+                       Uint32  ptaddr = pdir[i] & ~0xFFF;
+                       
+                       _ref_mem(refcount, ptaddr/PAGE_SIZE, proc, (void*)(i*1024*PAGE_SIZE));
+               }
+       }
+       
+       
+       for( tProcess *proc = gAllProcesses; proc; proc = proc->Next )
+       {
+               Uint    cr3 = proc->MemState.CR3;
+               
+               _load_page(tmp_pd, cr3);
+               const Uint32    *pdir = tmp_pd;
+               for(int i = 0; i < 1024; i ++)
+               {
+                       Uint32  pde = pdir[i];
+                       if( _should_skip_pde(proc, i, pde) )
+                               continue ;
+                       
+                       Uint32  ptaddr = pde & ~0xFFF;
+                       
+                       // 
+                       if( proc->PID == 0 || refcount[ ptaddr >> 12 ] == 1 )
+                       {
+                               _load_page(tmp_pt, ptaddr);
+                               Validate_VirtualMemoryUsage_PT(tmp_pt, proc, i, refcount);
+                       }
+               }
+       }
+       
+       for( int i = 0; i < giPageCount; i ++ )
+       {
+                int    recorded_refc = MM_GetRefCount(i*PAGE_SIZE);
+               
+               void    *node;
+               if( MM_GetPageNode(i*PAGE_SIZE, &node) == 0 && node != NULL )
+                       _ref_mem(refcount, i, NULL, 0);
+               
+               // 0x9F000 - BIOS memory area
+               // 0xA0000+ - ROM area
+               if( 0x9F <= i && i < 0x100 ) {
+                       _ref_mem(refcount, i, NULL, 0);
+               }
+               
+               if( recorded_refc != refcount[i] ) {
+                       Debug("Refcount mismatch %P - recorded %i != checked %i",
+                               (tPAddr)i*PAGE_SIZE, recorded_refc, refcount[i]);
+               }
+       }
+       
+       // Output.
+       for( tProcess *proc = gAllProcesses; proc; proc = proc->Next )
+       {
+               Debug("%p(%i %s)", proc, proc->PID, proc->FirstThread->ThreadName);
+               Uint    cr3 = proc->MemState.CR3;
+               
+               _load_page(tmp_pd, cr3);
+               const Uint32    *pdir = tmp_pd;
+               for(int i = 0; i < 1024; i ++)
+               {
+                       Uint32  pde = pdir[i];
+                       if( _should_skip_pde(proc, i, pde) )
+                               continue ;
+                       Uint32  paddr = pde & ~0xFFF;
+                       
+                       if( proc->PID != 0 && refcount[ paddr >> 12 ] > 1 )
+                               continue ;
+                       
+                       if( MM_GetRefCount(paddr) != refcount[paddr>>12] ) {
+                               Debug("Table %p(%i %s) @%p %P %i!=%i",
+                                       proc, proc->PID, proc->FirstThread->ThreadName,
+                                       i*1024*PAGE_SIZE, paddr,
+                                       MM_GetRefCount(paddr), refcount[paddr>>12]
+                                       );
+                       }
+       
+                       _load_page(tmp_pt, paddr);
+                       const Uint32 *ptab = tmp_pt;
+                       for( int j = 0; j < 1024; j ++ ) 
+                       {
+                               if( !(ptab[j] & 1) )
+                                       continue ;
+                               Uint32  pageaddr = ptab[j] & ~0xFFF;
+                               
+                               if( pageaddr/PAGE_SIZE >= giPageCount )
+                               {
+                                       //Debug("PG %p(%i %s) @%p %P not in RAM",
+                                       //      proc, proc->PID, proc->FirstThread->ThreadName,
+                                       //      (i*1024+j)*PAGE_SIZE, pageaddr
+                                       //      );
+                               }
+                               else if( MM_GetRefCount(pageaddr) != refcount[pageaddr>>12] ) {
+                                       Debug("PG %p(%i %s) @%p %P %i!=%i",
+                                               proc, proc->PID, proc->FirstThread->ThreadName,
+                                               (i*1024+j)*PAGE_SIZE, pageaddr,
+                                               MM_GetRefCount(pageaddr), refcount[pageaddr>>12]
+                                               );
+                               }
+                       }
+               }
+       }
+}
+
+void Validate_VirtualMemoryUsage_PT(const Uint32 *PTable, const tProcess *Proc, int PDIndex, int *RefCounts)
+{
+       for( int i = 0; i < 1024; i ++ )
+       {
+               // Ignore the 3GB+1MB area
+               if( PDIndex == 768 && i < 256 )
+                       continue ;
+               // And ignore anything from the end of the kernel up to 3GB4MB
+               if( PDIndex == 768 && i > ((tVAddr)gKernelEnd-KERNEL_BASE)/PAGE_SIZE )
+                       continue ;
+               
+               Uint32  pte = PTable[i];
+               if( !(pte & 1) )
+                       continue ;
+               
+               Uint32  paddr = pte & ~0xFFF;
+               Uint    page = paddr >> 12;
+               
+               _ref_mem(RefCounts, page, Proc, (void*)((PDIndex*1024+i)*PAGE_SIZE));
+       }
+}
+
+bool _should_skip_pde(const tProcess *Proc, int idx, Uint32 pde)
+{
+       if( !(pde & 1) )
+               return true;
+       
+       if( (pde & ~0xFFF) == Proc->MemState.CR3 ) {
+               return true;
+       }
+
+       if( idx == PAGE_TABLE_ADDR>>22 ) {
+               if( (pde & ~0xFFF) != Proc->MemState.CR3 ) {
+                       // Bad!
+               }
+       }       
+       
+       return false;
+}
+
+void _ref_mem(int *RefCounts, Uint PageNum, const tProcess *Proc, void *addr)
+{
+       if( PageNum == 0x1001000/PAGE_SIZE ) {
+               Debug("frame #0x%x %i:%p", PageNum, Proc?Proc->PID:-1, addr);
+       }
+       if( PageNum >= giPageCount )
+               ;
+       else
+               RefCounts[ PageNum ] ++;
+}
+
+void _load_page(Uint32 *dst, tPAddr phys)
+{
+       const void *src = MM_MapTemp(phys);
+       memcpy(dst, src, PAGE_SIZE);
+       MM_FreeTemp( (void*)src);
+}
+

UCC git Repository :: git.ucc.asn.au