X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Farch%2Fx86%2Fmm_virt.c;h=01843d9c92996bb280c9957d9218b92862e8a557;hb=7e9bbefbdcbfdba27eb6cdacae0811f428483892;hp=5e5ccd37b7d56f59d425ef13c6823d4835626fa1;hpb=b7d9f86f7a1c23be18b50d5c647fd5d3c08369c3;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/arch/x86/mm_virt.c b/KernelLand/Kernel/arch/x86/mm_virt.c index 5e5ccd37..01843d9c 100644 --- a/KernelLand/Kernel/arch/x86/mm_virt.c +++ b/KernelLand/Kernel/arch/x86/mm_virt.c @@ -23,14 +23,22 @@ #define TRACE_MAPS 0 +#define KWATCH_BUCKETS 512 + #define TAB 22 -#define PF_PRESENT 0x1 -#define PF_WRITE 0x2 -#define PF_USER 0x4 -#define PF_GLOBAL 0x80 -#define PF_COW 0x200 -#define PF_NOPAGE 0x400 +#define PF_PRESENT 0x01 +#define PF_WRITE 0x02 +#define PF_USER 0x04 +#define PF_PAGEWT 0x08 // Page-level write through +#define PF_PAGECD 0x10 // Page-level cache disable +#define PF_ACCESSED 0x20 +#define PF_DIRTY 0x40 +#define PF_PAT 0x80 // ? +#define PF_GLOBAL 0x100 // Global Page +#define PF_COW 0x200 // [ 9] Ignored - Copy-on-write +#define PF_NOPAGE 0x400 // [10] Ignored - Disable page-out +#define PF_WATCHED 0x800 // [11] Ignored - Watchpointing enabled #define INVLPG(addr) __asm__ __volatile__ ("invlpg (%0)"::"r"(addr)) @@ -53,12 +61,20 @@ extern Uint32 gaInitPageDir[1024]; extern Uint32 gaInitPageTable[1024]; extern void Threads_SegFault(tVAddr Addr); +typedef struct sWatchpoint +{ + struct sWatchpoint *Next; + Uint PageNum; + Uint8 Bitmap[PAGE_SIZE/4/8]; +} tWatchpoint; + // === PROTOTYPES === void MM_PreinitVirtual(void); void MM_InstallVirtual(void); void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs); void MM_DumpTables_Print(tVAddr Start, Uint32 Orig, size_t Size, void *Node); //void MM_DumpTables(tVAddr Start, tVAddr End); +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr); //void MM_ClearUser(void); tPAddr MM_DuplicatePage(tVAddr VAddr); @@ -92,6 +108,7 @@ struct sPageInfo { // - Zero page tShortSpinlock glMM_ZeroPage; tPAddr giMM_ZeroPage; +tWatchpoint *gapKernelWatchpoints[KWATCH_BUCKETS]; // === CODE === /** @@ -167,26 +184,27 @@ void MM_FinishVirtualInit(void) */ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) { + Uint32 *pde = &gaPageDir[Addr>>22]; + Uint32 *pte = &gaPageTable[Addr>>12]; //ENTER("xAddr bErrorCode", Addr, ErrorCode); // -- Check for COW -- - if( gaPageDir [Addr>>22] & PF_PRESENT && gaPageTable[Addr>>12] & PF_PRESENT - && gaPageTable[Addr>>12] & PF_COW ) + if( (*pde & PF_PRESENT) && (*pte & PF_PRESENT) && (*pte & PF_COW) ) { tPAddr paddr; __asm__ __volatile__ ("sti"); - if(MM_GetRefCount( gaPageTable[Addr>>12] & ~0xFFF ) == 1) + if( MM_GetRefCount( *pte & ~0xFFF ) == 1 ) { - gaPageTable[Addr>>12] &= ~PF_COW; - gaPageTable[Addr>>12] |= PF_PRESENT|PF_WRITE; + *pte &= ~PF_COW; + *pte |= PF_PRESENT|PF_WRITE; } else { //Log("MM_PageFault: COW - MM_DuplicatePage(0x%x)", Addr); paddr = MM_DuplicatePage( Addr ); - MM_DerefPhys( gaPageTable[Addr>>12] & ~0xFFF ); - gaPageTable[Addr>>12] &= PF_USER; - gaPageTable[Addr>>12] |= paddr|PF_PRESENT|PF_WRITE; + MM_DerefPhys( *pte & ~0xFFF ); + *pte &= PF_USER; + *pte |= paddr|PF_PRESENT|PF_WRITE; } // Log_Debug("MMVirt", "COW for %p (%P)", Addr, gaPageTable[Addr>>12]); @@ -195,6 +213,38 @@ void MM_PageFault(tVAddr Addr, Uint ErrorCode, tRegs *Regs) return; } + // --- Check for write to controlled area --- + // TODO: Catch user access + if( (*pde & PF_PRESENT) && (*pte & PF_PRESENT) && !(*pte & PF_WRITE) && (*pte & PF_WATCHED) ) + { + Uint page = Addr >> 12; + Uint ofs = Addr & 0xFFF; + // Watchpoints are active for this page. + // > Locate watchpoint bitmap for page (dword granuality) + tWatchpoint *wp = ( Addr >= KERNEL_BASE ? gapKernelWatchpoints[page%KWATCH_BUCKETS] : NULL); + while( wp && wp->PageNum == page ) + wp = wp->Next; + if( !wp ) + { + Log_Warning("MMVirt", "PF_WATCHED set on %p but no watchpoint info avaliable", Addr); + } + else + { + // > If bit set, log/raise + if( wp->Bitmap[ (ofs/4)/8 ] & (1 << (ofs/4)%8) ) + { + Log_Error("DEBUG", "Watchpoint %p written by %x:%p", + Addr, Regs->cs, Regs->eip); + } + Regs->eflags |= 1<<8; + //Proc_GetCurThread()->Proc.WPPage = Addr; + } + // > Clear write protection, set tracing + *pte |= PF_WRITE; + INVLPG( Addr & ~0xFFF ); + return ; + } + // Disable instruction tracing __ASM__("pushf; andw $0xFEFF, 0(%esp); popf"); Proc_GetCurThread()->bInstrTrace = 0; @@ -261,7 +311,7 @@ void MM_DumpTables_Print(tVAddr Start, Uint32 Orig, size_t Size, void *Node) { if( (Orig & ~(PAGE_SIZE-1)) == giMM_ZeroPage ) { - Log( "0x%08x => ZERO + 0x%08x (%s%s%s%s%s) %p", + Log(" 0x%08x => ZERO + 0x%08x (%s%s%s%s%s) %p", Start, Size, (Orig & PF_NOPAGE ? "P" : "-"), @@ -489,6 +539,23 @@ tPAddr MM_GetPhysAddr(volatile const void *Addr) return (gaPageTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF); } +/** + * \brief Get the address of a page from another addres space + * \return Refenced physical address (or 0 on error) + */ +tPAddr MM_GetPageFromAS(tProcess *Process, volatile const void *Addr) +{ + tPAddr ret = 0; + GET_TEMP_MAPPING(Process->MemState.CR3); + tVAddr addr = (tVAddr)Addr; + if( (gaTmpDir[addr >> 22] & 1) && (gaTmpTable[addr >> 12] & 1) ) { + ret = (gaTmpTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF); + MM_RefPhys( ret ); + } + REL_TEMP_MAPPING(); + return ret; +} + /** * \fn void MM_SetCR3(Uint CR3) * \brief Sets the current process space @@ -503,18 +570,17 @@ void MM_SetCR3(Uint CR3) */ void MM_ClearUser(void) { - Uint i, j; - - for( i = 0; i < (MM_USER_MAX>>22); i ++ ) + ASSERTC(MM_PPD_MIN, ==, MM_USER_MAX); + for( unsigned int i = 0; i < (MM_USER_MAX>>22); i ++ ) { // Check if directory is not allocated if( !(gaPageDir[i] & PF_PRESENT) ) { gaPageDir[i] = 0; continue; } - + // Deallocate tables - for( j = 0; j < 1024; j ++ ) + for( unsigned int j = 0; j < 1024; j ++ ) { if( gaPageTable[i*1024+j] & 1 ) MM_DerefPhys( gaPageTable[i*1024+j] & ~0xFFF ); @@ -534,8 +600,6 @@ void MM_ClearUser(void) */ void MM_ClearSpace(Uint32 CR3) { - int i, j; - if(CR3 == (*gpPageCR3 & ~0xFFF)) { Log_Error("MMVirt", "Can't clear current address space"); return ; @@ -552,7 +616,7 @@ void MM_ClearSpace(Uint32 CR3) GET_TEMP_MAPPING(CR3); INVLPG( gaTmpDir ); - for( i = 0; i < 1024; i ++ ) + for( int i = 0; i < 1024; i ++ ) { Uint32 *table = &gaTmpTable[i*1024]; if( !(gaTmpDir[i] & PF_PRESENT) ) @@ -562,7 +626,7 @@ void MM_ClearSpace(Uint32 CR3) if( i < 768 || (i > MM_KERNEL_STACKS >> 22 && i < MM_KERNEL_STACKS_END >> 22) ) { - for( j = 0; j < 1024; j ++ ) + for( int j = 0; j < 1024; j ++ ) { if( !(table[j] & 1) ) continue; @@ -1003,6 +1067,8 @@ void *MM_MapTemp(tPAddr PAddr) LOG("%i: %x", i, *pte); // Check if page used if(*pte & 1) continue; + MM_RefPhys( PAddr ); + // Mark as used *pte = PAddr | 3; INVLPG( TEMP_MAP_ADDR + (i << 12) ); @@ -1015,6 +1081,15 @@ void *MM_MapTemp(tPAddr PAddr) return NULL; } +void *MM_MapTempFromProc(tProcess *Process, const void *VAddr) +{ + // Get paddr + tPAddr paddr = MM_GetPageFromAS(Process, VAddr); + if( paddr == 0 ) + return NULL; + return MM_MapTemp(paddr); +} + /** * \fn void MM_FreeTemp(tVAddr PAddr) * \brief Free's a temp mapping @@ -1024,7 +1099,9 @@ void MM_FreeTemp(void *VAddr) int i = (tVAddr)VAddr >> 12; //ENTER("xVAddr", VAddr); - if(i >= (TEMP_MAP_ADDR >> 12)) { + if(i >= (TEMP_MAP_ADDR >> 12)) + { + MM_DerefPhys( gaPageTable[i] & ~0xFFF ); gaPageTable[ i ] = 0; Semaphore_Signal(&gTempMappingsSem, 1); }