Phoenix
Object-oriented orthogonally persistent operating system
md_vm.h
Go to the documentation of this file.
00001 /*
00002  * /phoenix/kernel/sys/arch/x86_64/vm_md.h
00003  *
00004  * This file is a part of Phoenix operating system.
00005  * Copyright (c) 2011-2012, Artyom Lebedev <artyom.lebedev@gmail.com>
00006  * All rights reserved.
00007  * See COPYING file for copyright details.
00008  */
00009 
00010 #ifndef MD_VM_H_
00011 #define MD_VM_H_
00012 
00017 namespace vm {
00018 
00019 enum {
00021     PAGE_SHIFT =            12,
00022 
00024     NUM_LAT_TABLES =        4,
00025 };
00026 
00028 typedef u64 PageIdx;
00029 
00031 typedef u32 LatEntryIdx;
00032 
00034 typedef u32 ProcCtxId;
00035 
00040 class VaddrDecoder {
00041 public:
00043     inline VaddrDecoder(vaddr_t va = 0) { _va.va = va; }
00044 
00051     static inline u32 GetTableSize(u32 UNUSED tableLvl) {
00052         ASSERT(tableLvl < NUM_LAT_TABLES);
00053         /* 512 entries in eachLatEntrytable. */
00054         return 512;
00055     }
00056 
00063     inline LatEntryIdx GetEntryIndex(u32 tableLvl) {
00064         switch (tableLvl) {
00065         case 0:
00066             return _va.fields.tblIdx0;
00067         case 1:
00068             return _va.fields.tblIdx1;
00069         case 2:
00070             return _va.fields.tblIdx2;
00071         case 3:
00072             return _va.fields.tblIdx3;
00073         }
00074         FAULT("Table index is out of range: %d", tableLvl);
00075         return 0;
00076     }
00077 
00079     inline vaddr_t GetPageOffset() {
00080         return _va.fields.pageOffset;
00081     }
00082 
00083 private:
00084     struct VaFields {
00085         vaddr_t     pageOffset:PAGE_SHIFT,
00086                     tblIdx0:9, /* Page table */
00087                     tblIdx1:9, /* Page directory */
00088                     tblIdx2:9, /* Page directory pointers table */
00089                     tblIdx3:9, /* PML4 */
00090                     :16;
00091     };
00092 
00093     volatile union {
00094         vaddr_t va;
00095         VaFields fields;
00096     } _va;
00097 };
00098 
00100 class LatEntry {
00101 public:
00102     inline LatEntry() {
00103         _ptr.raw = 0;
00104         _tableLvl = 0;
00105     }
00106 
00114     inline LatEntry(vaddr_t va, void *table, u32 tableLvl = 0) {
00115         Set(va, table, tableLvl);
00116     }
00117 
00123     inline LatEntry(void *entry, u32 tableLvl = 0) {
00124         Set(entry, tableLvl);
00125     }
00126 
00134     inline void Set(vaddr_t va, void *table, u32 tableLvl = 0) {
00135         ASSERT(tableLvl <= NUM_LAT_TABLES);
00136         _tableLvl = tableLvl;
00137         _ptr.ptr = table;
00138         VaddrDecoder dec(va);
00139         _ptr.raw += dec.GetEntryIndex(tableLvl);
00140     }
00141 
00147     inline void Set(void *entry, u32 tableLvl = 0) {
00148         ASSERT(tableLvl <= NUM_LAT_TABLES);
00149         _tableLvl = tableLvl;
00150         _ptr.ptr = entry;
00151     }
00152 
00157     inline bool IsAccessed() {
00158         if (_tableLvl == NUM_LAT_TABLES) {
00159             /* CR3 does not have the flag. */
00160             return false;
00161         }
00162         return _ptr.entryPage->accessed;
00163     }
00164 
00170     inline bool SetAccessed(bool flag = true) {
00171         if (_tableLvl == NUM_LAT_TABLES) {
00172             /* CR3 does not have the flag. */
00173             return false;
00174         }
00175         bool curFlag = _ptr.entryPage->accessed;
00176         _ptr.entryPage->accessed = flag;
00177         return curFlag;
00178     }
00179 
00184     inline bool IsDirty() {
00185         if (_tableLvl == NUM_LAT_TABLES) {
00186             /* CR3 does not have the flag. */
00187             return false;
00188         }
00189         return _ptr.entryPage->dirty;
00190     }
00191 
00197     inline bool SetDirty(bool flag = true) {
00198         if (_tableLvl == NUM_LAT_TABLES) {
00199             /* CR3 does not have the flag. */
00200             return false;
00201         }
00202         bool curFlag = _ptr.entryPage->dirty;
00203         _ptr.entryPage->dirty = flag;
00204         return curFlag;
00205     }
00206 
00211     bool CheckFlag(LatEntryFlags flag) {
00212         ASSERT(_tableLvl <= NUM_LAT_TABLES);
00213         if (_tableLvl == NUM_LAT_TABLES) {
00214             switch (flag) {
00215             case LAT_EF_WRITE_THROUGH:
00216                 return _ptr.cr3->pwt;
00217             case LAT_EF_CACHE_DISABLE:
00218                 return _ptr.cr3->pcd;
00219             default:
00220                 return false;
00221             }
00222         }
00223         switch (flag) {
00224         case LAT_EF_PRESENT:
00225             return _ptr.entryPage->present;
00226         case LAT_EF_WRITE:
00227             return _ptr.entryPage->write;
00228         case LAT_EF_USER:
00229             return _ptr.entryPage->user;
00230         case LAT_EF_WRITE_THROUGH:
00231             return _ptr.entryPage->writeThrough;
00232         case LAT_EF_CACHE_DISABLE:
00233             return _ptr.entryPage->cacheDisable;
00234         case LAT_EF_EXECUTE:
00235             return !_ptr.entryPage->executeDisable;
00236         case LAT_EF_GLOBAL:
00237             return _ptr.entryPage->global;
00238         }
00239         FAULT("Invalid flag specified: %d", flag);
00240         return false;
00241     }
00242 
00250     bool SetFlag(LatEntryFlags flag, bool setIt = true) {
00251         bool prev;
00252         ASSERT(_tableLvl <= NUM_LAT_TABLES);
00253         if (_tableLvl == NUM_LAT_TABLES) {
00254             switch (flag) {
00255             case LAT_EF_WRITE_THROUGH:
00256                 prev = _ptr.cr3->pwt;
00257                 _ptr.cr3->pwt = setIt ? 1 : 0;
00258                 break;
00259             case LAT_EF_CACHE_DISABLE:
00260                 prev = _ptr.cr3->pcd;
00261                 _ptr.cr3->pcd = setIt ? 1 : 0;
00262                 break;
00263             default:
00264                 prev = false;
00265                 break;
00266             }
00267             return prev;
00268         }
00269         switch (flag) {
00270         case LAT_EF_PRESENT:
00271             prev = _ptr.entryPage->present;
00272             _ptr.entryPage->present = setIt ? 1 : 0;
00273             break;
00274         case LAT_EF_WRITE:
00275             prev = _ptr.entryPage->write;
00276             _ptr.entryPage->write = setIt ? 1 : 0;
00277             break;
00278         case LAT_EF_USER:
00279             prev = _ptr.entryPage->user;
00280             _ptr.entryPage->user = setIt ? 1 : 0;
00281             break;
00282         case LAT_EF_WRITE_THROUGH:
00283             prev = _ptr.entryPage->writeThrough;
00284             _ptr.entryPage->writeThrough = setIt ? 1 : 0;
00285             break;
00286         case LAT_EF_CACHE_DISABLE:
00287             prev = _ptr.entryPage->cacheDisable;
00288             _ptr.entryPage->cacheDisable = setIt ? 1 : 0;
00289             break;
00290         case LAT_EF_EXECUTE:
00291             prev = !_ptr.entryPage->executeDisable;
00292             if (vmCaps.IsValid() && vmCaps.nx) {
00293                 _ptr.entryPage->executeDisable = setIt ? 0 : 1;
00294             }
00295             break;
00296         case LAT_EF_GLOBAL:
00297             prev = _ptr.entryPage->global;
00298             if (_tableLvl == 0 && vmCaps.IsValid() && vmCaps.pge) {
00299                 _ptr.entryPage->global = setIt ? 1 : 0;
00300             }
00301             break;
00302         default:
00303             FAULT("Invalid flag specified: %d", flag);
00304             break;
00305         }
00306         return prev;
00307     }
00308 
00316     long SetFlags(long flags) {
00317         static const LatEntryFlags allFlags[] = {
00318             LAT_EF_PRESENT,
00319             LAT_EF_WRITE,
00320             LAT_EF_USER,
00321             LAT_EF_WRITE_THROUGH,
00322             LAT_EF_CACHE_DISABLE,
00323             LAT_EF_EXECUTE,
00324             LAT_EF_GLOBAL
00325         };
00326         long prev;
00327 
00328         for (auto flag: allFlags) {
00329             if (SetFlag(flag, flags & flag)) {
00330                 prev |= flag;
00331             }
00332         }
00333         return prev;
00334     }
00335 
00337     inline paddr_t GetAddress() {
00338         return _ptr.entryPage->pa << PAGE_SHIFT;
00339     }
00340 
00345     inline paddr_t SetAddress(paddr_t pa) {
00346         ASSERT((pa & ((1 << PAGE_SHIFT) - 1)) == 0);
00347         paddr_t prevPa = _ptr.entryPage->pa << PAGE_SHIFT;
00348         _ptr.entryPage->pa = pa >> PAGE_SHIFT;
00349         return prevPa;
00350     }
00351 
00353     inline void Clear() { *_ptr.raw = 0; }
00354 
00358     inline operator paddr_t() { return GetAddress(); }
00359 
00365     inline LatEntry &operator=(paddr_t pa) { SetAddress(pa); return *this; }
00366 
00370     inline operator void *() { return _ptr.ptr; }
00371 
00377     inline ProcCtxId GetProcCtxId() {
00378         ENSURE(_tableLvl == NUM_LAT_TABLES);
00379         return _ptr.cr3->pcid;
00380     }
00381 
00387     inline ProcCtxId SetProcCtxId(ProcCtxId pcid) {
00388         ENSURE(_tableLvl == NUM_LAT_TABLES);
00389         ProcCtxId oldPcid = _ptr.cr3->pcid;
00390         if (vmCaps.IsValid() && vmCaps.pcid) {
00391             _ptr.cr3->pcid = pcid;
00392         }
00393         return oldPcid;
00394     }
00395 
00399     inline void Activate() {
00400         ENSURE(_tableLvl == NUM_LAT_TABLES);
00401         cpu::wcr3(*_ptr.raw);
00402     }
00403 
00404 private:
00405 
00407     struct EntryCr3 {
00408         union {
00409             /* CR4.PCIDE = 0 */
00410             paddr_t :3,
00411                     pwt:1,
00412                     pcd:1,
00413                     :7,
00414                     pa:40,
00415                     :12;
00416             /* CR4.PCIDE = 1 */
00417             paddr_t pcid:12;
00418         };
00419     };
00420 
00422     struct EntryPage {
00423         paddr_t     
00424                     present:1,
00426                     write:1,
00428                     user:1,
00430                     writeThrough:1,
00432                     cacheDisable:1,
00436                     accessed:1,
00440                     dirty:1,
00442                     pat:1,
00446                     global:1,
00447                     :3,
00449                     pa:40,
00450                     :11,
00452                     executeDisable:1;
00453     };
00454 
00456     struct EntryTable {
00457         paddr_t     
00458                     present:1,
00460                     write:1,
00462                     user:1,
00464                     writeThrough:1,
00466                     cacheDisable:1,
00470                     accessed:1,
00471                     :1,
00479                     pageSize:1,
00480                     :4,
00482                     pa:40,
00483                     :11,
00485                     executeDisable:1;
00486     };
00487 
00488     volatile union EntryPtr {
00489         void *ptr;
00490         paddr_t *raw;
00491         EntryCr3 *cr3;
00492         EntryPage *entryPage;
00493         EntryTable *entryTable;
00494     } _ptr;
00495 
00496     u32 _tableLvl;
00497 };
00498 
00503 inline void
00504 InvalidateVaddr(vaddr_t va)
00505 {
00506     cpu::invlpg(va);
00507 }
00508 
00510 inline void
00511 InitPaging(bool enablePaging)
00512 {
00513     if (enablePaging) {
00514         u64 cr0 = cpu::rcr0();
00515         if (!(cr0 & cpu_reg::CR0_PG)) {
00516             cpu::wcr0(cr0 | cpu_reg::CR0_PG);
00517         }
00518     } else {
00519         cpu::CpuCaps caps;
00520 
00521         /* Enable "execute-disable" feature if available. */
00522         if (caps.GetCapability(cpu::CPU_CAP_PG_NX)) {
00523             cpu::wrmsr(cpu_reg::MSR_IA32_EFER,
00524                        cpu::rdmsr(cpu_reg::MSR_IA32_EFER) | cpu_reg::IA32_EFER_NXE);
00525         }
00526 
00527         u64 features = cpu::rcr4();
00528         /* Enable global pages if available. */
00529         if (caps.GetCapability(cpu::CPU_CAP_PG_PGE)) {
00530             features |= cpu_reg::CR4_PGE;
00531         }
00532         /* Enable process context identification if available. */
00533         if (caps.GetCapability(cpu::CPU_CAP_PG_PCID)) {
00534             features |= cpu_reg::CR4_PCDIE;
00535         }
00536         cpu::wcr4(features);
00537     }
00538 }
00539 
00540 } /* namespace vm */
00541 
00542 #endif /* MD_VM_H_ */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines