1 using System;
  2 using System.Collections;
  3 
  4 namespace cmsx.machine
  5 {
  6     public enum Protection : byte
  7     {
  8         notPresent = 0u
  9         execute = 1u << 0u
 10         write = 1u << 1u
 11         read = 1u << 2u
 12         copyOnWrite = execute | write | read
 13     }
 14 
 15     public const byte textSegmentIndex = 0u;
 16     public const byte dataSegmentIndex = 1u;
 17     public const byte poolSegmentIndex = 2u;
 18     public const byte stackSegmentIndex = 3u;
 19     public const byte numSegments = 4u;
 20     public const ulong pageSize = 0x1000u;
 21     public const ulong pageOffsetMask = 0x0FFFu;
 22     public const byte pageOffsetBits = 12u;
 23     public const ushort numPtesInPage = 512u;
 24     public const ushort numDirectTranslationCaches = 16u;
 25     public const int numTranslationCacheEntries = 4096;
 26     public const ulong translationCacheIndexMask = (4096u / numSegments) - 1u;
 27     public const int numTranslationCacheIndexSegmentEntries = 1024;
 28     public const ushort numSegmentPageEntriesInRootPage = numPtesInPage / numSegments;
 29     public const ushort numDirectEntries = numSegmentPageEntriesInRootPage - 3u;
 30     public const ushort pteOffsetMask = 0x1FFu;
 31     //public const ushort pteOffsetMask = 0x3u; 
 32     public const byte numPteBits = 9u;
 33     //public const byte numPteBits = 2u;
 34     public const ushort maxDigit = 511u;
 35     //public const ushort maxDigit = 3u;
 36     public const ulong textSegmentBaseAddress = 0x0000000000000000u;
 37     public const ulong dataSegmentBaseAddress = 0x2000000000000000u;
 38     public const ulong poolSegmentBaseAddress = 0x4000000000000000u;
 39     public const ulong stackSegmentBaseAddress = 0x6000000000000000u;
 40     public const ulong kernelBaseAddress = 0x8000000000000000u;
 41     public const ushort kernelAddressSpaceNumber = 0u;
 42     public const ulong invalidAddress = cast<ulong>(-1);
 43     public const byte segmentNumberShift = 61u;
 44     public const byte segmentNumberMask = 0x03u;
 45     public const ulong m2Mask = ~cast<ulong>(1u);
 46     public const ulong m4Mask = ~cast<ulong>(3u);
 47     public const ulong m8Mask = ~cast<ulong>(7u);
 48     public const byte numAddressSpaceBits = 10u;
 49     public const ulong addressSpaceMask = (cast<ulong>(1u) << numAddressSpaceBits) - 1u;
 50     public const ulong invalidAddrSpaceMask = ~addressSpaceMask;
 51     public const byte numProtectionBits = 3u;
 52     public const ulong protectionMask = (cast<ulong>(1u) << numProtectionBits) - 1u;
 53     public const byte numVirtualAddressBits = 48u;
 54     public const ulong virtualAddressBase = cast<ulong>(1u) << numVirtualAddressBits;
 55     public const ulong virtualAddressBaseMask = virtualAddressBase - 1u;
 56     public const ulong kernelDataBaseAddress = kernelBaseAddress;
 57     public const ulong interruptVectorBaseAddress = kernelDataBaseAddress + dataSegmentBaseAddress + 512u;
 58     public const ulong interruptVectorEndAddress = interruptVectorBaseAddress + cast<ulong>(irqMax) * 8u;
 59     public const int maxTraps = 256;
 60     public const ulong trapTableBaseAddress = interruptVectorEndAddress;
 61     public const ulong trapTableEndAddress = trapTableBaseAddress + cast<ulong>(maxTraps) * 8u;
 62 
 63     private bool useTranslationCache = true;
 64 
 65     public inline nothrow bool UseTranslationCache()
 66     {
 67         return useTranslationCache;
 68     }
 69 
 70     public nothrow bool GetUseTranslationCache()
 71     {
 72         return useTranslationCache;
 73     }
 74 
 75     public nothrow void SetUseTranslationCacheValue(bool use)
 76     {
 77         useTranslationCache = use;
 78     }
 79 
 80     public delegate ulong KernelMaxStackSizeFunction(ushort addressSpaceNumber);
 81     public delegate bool KernelGrowStackFunction(ushort addressSpaceNumber);
 82 
 83     private KernelMaxStackSizeFunction kernelMaxStackSizeFunction;
 84     private KernelGrowStackFunction kernelGrowStackFunction;
 85 
 86     public nothrow void SetKernelMaxStackSizeFunction(KernelMaxStackSizeFunction kernelMaxStackSizeFunction_)
 87     {
 88         kernelMaxStackSizeFunction = kernelMaxStackSizeFunction_;
 89     }
 90 
 91     public nothrow void SetKernelGrowStackFunction(KernelGrowStackFunction kernelGrowStackFunction_)
 92     {
 93         kernelGrowStackFunction = kernelGrowStackFunction_;
 94     }
 95 
 96     public nothrow ulong GetMaxStackSize(ushort addressSpaceNumber)
 97     {
 98         if (cast<void*>(kernelMaxStackSizeFunction) == null)
 99         {
100             return 0u;
101         }
102         else
103         {
104             return kernelMaxStackSizeFunction(addressSpaceNumber);
105         }
106     }
107 
108     public nothrow bool GrowStack(ushort addressSpaceNumber)
109     {
110         if (cast<void*>(kernelGrowStackFunction) == null)
111         {
112             return false;
113         }
114         else
115         {
116             return kernelGrowStackFunction(addressSpaceNumber);
117         }
118     }
119 
120     public class PageFrame
121     {
122         public nothrow PageFrame() : useCount(1u)
123         {
124         }
125         public byte useCount;
126     }
127 
128     public string GetProtectionStr(Protection protection)
129     {
130         string s;
131         if (protection != Protection.notPresent)
132         {
133             if (protection == Protection.copyOnWrite)
134             {
135                 s = s + "COW";
136             }
137             else
138             {
139                 if ((protection & Protection.read) != Protection.notPresent)
140                 {
141                     s = s + "R";
142                 }
143                 if ((protection & Protection.write) != Protection.notPresent)
144                 {
145                     s = s + "W";
146                 }
147                 if ((protection & Protection.execute) != Protection.notPresent)
148                 {
149                     s = s + "X";
150                 }
151             }
152         }
153         else
154         {
155             s = s + "-";
156         }
157         return s;
158     }
159 
160     public nothrow void PrintAddressValues(bool getushort addressSpaceNumberulong pageAddressint entryIndexulong sourcePageNumber)
161     {
162         string getSetStr = "get";
163         if (!get)
164         {
165             getSetStr = "set";
166         }
167         Console.Out() << getSetStr << ": space=" << addressSpaceNumber << ", page=" << ToHexString(pageAddress) << ", entry=" << entryIndex << ", source=" << ToHexString(sourcePageNumber) << endl();
168     }
169 
170     public inline nothrow ulong GetPageNumber(ulong address)
171     {
172         ulong pageNumber = address / pageSize;
173         return pageNumber;
174     }
175 
176     public inline nothrow ulong MakeVirtualTranslationRegisterValue(ulong rootPageAddressushort addressSpaceNumber)
177     {
178         return (rootPageAddress << numAddressSpaceBits) | cast<ulong>(addressSpaceNumber);
179     }
180 
181     public inline nothrow void UnpackVirtualTranslationRegisterValue(ulong virtualTranslationRegisterValueulong& rootPageAddressushort& addressSpaceNumber)
182     {
183         rootPageAddress = virtualTranslationRegisterValue >> numAddressSpaceBits;
184         addressSpaceNumber = cast<ushort>(virtualTranslationRegisterValue & addressSpaceMask);
185     }
186 
187     public inline nothrow ulong PackProtection(Protection pageProtectionProtection protection)
188     {
189         return (cast<ulong>(cast<byte>(pageProtection)) << 8u) | cast<ulong>(cast<byte>(protection));
190     }
191 
192     public inline nothrow void UnpackProtection(ulong packedValueProtection& pageProtectionProtection& protection)
193     {
194         protection = cast<Protection>(cast<byte>(packedValue));
195         packedValue = packedValue >> 8u;
196         pageProtection = cast<Protection>(cast<byte>(packedValue));
197     }
198 
199     public inline nothrow ulong MakePageTableEntry(ulong pageAddressushort addressSpaceNumberProtection protection)
200     {
201         ulong pte = (pageAddress << 13u) | (cast<ulong>(addressSpaceNumber) << 3u) | cast<ulong>(cast<byte>(protection));
202         return pte;
203     }
204 
205     public inline nothrow void UnpackPageTableEntry(ulong pteulong& pageAddressushort& addressSpaceNumberProtection& protection)
206     {
207         pageAddress = pte >> 13u;
208         addressSpaceNumber = cast<ushort>((pte >> 3u) & addressSpaceMask);
209         protection = cast<Protection>(cast<byte>(pte & protectionMask));
210     }
211 
212     public nothrow Protection MakeDefaultPageProtection(byte segmentIndex)
213     {
214         switch (segmentIndex)
215         {
216             case textSegmentIndex: return cast<Protection>(Protection.read | Protection.execute);
217             case dataSegmentIndex: return cast<Protection>(Protection.read | Protection.write);
218             case poolSegmentIndex: return cast<Protection>(Protection.read | Protection.write);
219             case stackSegmentIndex: return cast<Protection>(Protection.read | Protection.write);
220         }
221         return Protection.notPresent;
222     }
223 
224     public inline nothrow byte GetSegmentIndex(ulong virtualAddress)
225     {
226         return cast<byte>((virtualAddress >> segmentNumberShift) & segmentNumberMask);
227     }
228 
229     public inline nothrow ulong GetSegmentPart(ulong virtualAddress)
230     {
231         return cast<ulong>(GetSegmentIndex(virtualAddress)) << cast<ulong>(segmentNumberShift);
232     }
233 
234     public inline nothrow ushort MakeSegmentOffset(byte segmentIndex)
235     {
236         return segmentIndex * numSegmentPageEntriesInRootPage;
237     }
238 
239     public inline nothrow void ExtractDigitsFromPageNumber(ulong pageNumushort& digit0ushort& digit1ushort& digit2)
240     {
241         digit0 = cast<ushort>(pageNum & pteOffsetMask);
242         pageNum = pageNum >> numPteBits;
243         digit1 = cast<ushort>(pageNum & pteOffsetMask);
244         pageNum = pageNum >> numPteBits;
245         digit2 = cast<ushort>(pageNum & pteOffsetMask);
246         pageNum = pageNum >> numPteBits;
247     }
248 
249     public nothrow byte ReadMemoryByte(ulong address)
250     {
251         byte b = OsReadMemoryByte(address);
252         return b;
253     }
254 
255     public nothrow void WriteMemoryByte(ulong addressbyte b)
256     {
257         if (address == 0u)
258         {
259             return;
260         }
261         OsWriteMemoryByte(addressb);
262     }
263 
264     public nothrow ushort ReadMemoryUShort(ulong address)
265     {
266         ulong a = address & m2Mask;
267         byte m0 = ReadMemoryByte(a);
268         byte m1 = ReadMemoryByte(a + 1u);
269         ushort u = (cast<ushort>(m0) << 8u) | cast<ushort>(m1);
270         return u;
271     }
272 
273     public nothrow void WriteMemoryUShort(ulong addressushort s)
274     {
275         ulong a = address & m2Mask;
276         byte m0 = cast<byte>(s >> 8u);
277         byte m1 = cast<byte>(s);
278         WriteMemoryByte(am0);
279         WriteMemoryByte(a + 1um1);
280     }
281 
282     public nothrow uint ReadMemoryUInt(ulong address)
283     {
284         ulong a = address & m4Mask;
285         byte m0 = ReadMemoryByte(a);
286         byte m1 = ReadMemoryByte(a + 1u);
287         byte m2 = ReadMemoryByte(a + 2u);
288         byte m3 = ReadMemoryByte(a + 3u);
289         uint u = (cast<uint>(m0) << 24u) | (cast<uint>(m1) << 16u) | (cast<uint>(m2) << 8u) | cast<uint>(m3);
290         return u;
291     }
292 
293     public nothrow void WriteMemoryUInt(ulong addressuint u)
294     {
295         ulong a = address & m4Mask;
296         byte m0 = cast<byte>(u >> 24u);
297         byte m1 = cast<byte>(u >> 16u);
298         byte m2 = cast<byte>(u >> 8u);
299         byte m3 = cast<byte>(u);
300         WriteMemoryByte(am0);
301         WriteMemoryByte(a + 1um1);
302         WriteMemoryByte(a + 2um2);
303         WriteMemoryByte(a + 3um3);
304     }
305 
306     public nothrow ulong ReadMemoryULong(ulong address)
307     {
308         ulong a = address & m8Mask;
309         byte m0 = ReadMemoryByte(a);
310         byte m1 = ReadMemoryByte(a + 1u);
311         byte m2 = ReadMemoryByte(a + 2u);
312         byte m3 = ReadMemoryByte(a + 3u);
313         byte m4 = ReadMemoryByte(a + 4u);
314         byte m5 = ReadMemoryByte(a + 5u);
315         byte m6 = ReadMemoryByte(a + 6u);
316         byte m7 = ReadMemoryByte(a + 7u);
317         ulong u = (cast<ulong>(m0) << 56u) | (cast<ulong>(m1) << 48u) | (cast<ulong>(m2) << 40u) | (cast<ulong>(m3) << 32u) | (cast<ulong>(m4) << 24u) | (cast<ulong>(m5) << 16u) | (cast<ulong>(m6) << 8u) | cast<ulong>(m7);
318         return u;
319     }
320 
321     public nothrow void WriteMemoryULong(ulong addressulong u)
322     {
323         ulong a = address & m8Mask;
324         byte m0 = cast<byte>(u >> 56u);
325         byte m1 = cast<byte>(u >> 48u);
326         byte m2 = cast<byte>(u >> 40u);
327         byte m3 = cast<byte>(u >> 32u);
328         byte m4 = cast<byte>(u >> 24u);
329         byte m5 = cast<byte>(u >> 16u);
330         byte m6 = cast<byte>(u >> 8u);
331         byte m7 = cast<byte>(u);
332         WriteMemoryByte(am0);
333         WriteMemoryByte(a + 1um1);
334         WriteMemoryByte(a + 2um2);
335         WriteMemoryByte(a + 3um3);
336         WriteMemoryByte(a + 4um4);
337         WriteMemoryByte(a + 5um5);
338         WriteMemoryByte(a + 6um6);
339         WriteMemoryByte(a + 7um7);
340     }
341 
342     public class AddressTranslationCacheEntry
343     {
344         public nothrow AddressTranslationCacheEntry() : sourcePageNumber(invalidAddress)targetPageNumber(invalidAddress)
345         {
346         }
347         public ulong sourcePageNumber;
348         public ulong targetPageNumber;
349     }
350 
351     public class AddressTranslationCache
352     {
353         public nothrow AddressTranslationCache() : entries()
354         {
355         }
356         public nothrow void Clear()
357         {
358             for (int i = 0; i < numTranslationCacheEntries; ++i;)
359             {
360                 entries[i] = AddressTranslationCacheEntry();
361             }
362         }
363         public inline nothrow ulong GetEntry(ulong virtualAddressint& entryIndexulong& sourcePageNumber)
364         {
365             entryIndex = cast<int>((virtualAddress >> pageOffsetBits) & translationCacheIndexMask) + numTranslationCacheIndexSegmentEntries * cast<int>(GetSegmentIndex(virtualAddress));
366             sourcePageNumber = GetSegmentPart(virtualAddress) | GetPageNumber(virtualAddress & virtualAddressBaseMask);
367             const AddressTranslationCacheEntry& entry = entries[entryIndex];
368             if (entry.sourcePageNumber == sourcePageNumber)
369             {
370                 return entry.targetPageNumber;
371             }
372             else
373             {
374                 return invalidAddress;
375             }
376         }
377         public inline nothrow void SetEntry(int entryIndexulong sourcePageNumberulong targetPageNumber)
378         {
379             AddressTranslationCacheEntry& entry = entries[entryIndex];
380             entry.sourcePageNumber = sourcePageNumber;
381             entry.targetPageNumber = targetPageNumber;
382         }
383         public AddressTranslationCacheEntry[numTranslationCacheEntries] entries;
384     }
385 
386     public class Memory
387     {
388         public nothrow Memory(Machine& machine_) : machine(machine_)
389         {
390         }
391         public ulong AllocatePage()
392         {
393             ulong pageAddress = OsAllocateMemoryPage(pageSize);
394             if (pageAddress == 0u)
395             {
396                 Console.Error() << "out of memory" << endl();
397                 throw Exception("out of memory");
398             }
399             pageFrameMap[pageAddress] = new PageFrame();
400             return pageAddress;
401         }
402         public ulong AllocateRootPage()
403         {
404             ulong rootPageAddress = AllocatePage();
405             return rootPageAddress;
406         }
407         public void FreePage(ulong pageAddress)
408         {
409             HashMap<ulongPageFrame*>.ConstIterator it = pageFrameMap.CFind(pageAddress);
410             if (it != pageFrameMap.CEnd())
411             {
412                 PageFrame* pageFrame = it->second;
413                 #assert(pageFrame->useCount > 0u);
414                 pageFrame->useCount = pageFrame->useCount - 1u;
415                 if (pageFrame->useCount == 0u)
416                 {
417                     OsFreeMemoryPage(pageAddress);
418                     pageFrameMap.Remove(pageAddress);
419                     delete pageFrame;
420                 }
421             }
422             else
423             {
424                 Panic("page frame for page address " + ToHexString(pageAddress) + " not found");
425             }
426         }
427         public nothrow void FreeRootPage(ulong rootPageAddress)
428         {
429             FreePage(rootPageAddress);
430         }
431         public void SharePage(ulong pageAddress)
432         {
433             HashMap<ulongPageFrame*>.ConstIterator it = pageFrameMap.CFind(pageAddress);
434             if (it != pageFrameMap.CEnd())
435             {
436                 PageFrame* pageFrame = it->second;
437                 #assert(pageFrame->useCount > 0u);
438                 pageFrame->useCount = pageFrame->useCount + 1u;
439             }
440             else
441             {
442                 Panic("page frame for page address " + ToHexString(pageAddress) + " not found");
443             }
444         }
445         public nothrow void CopyPage(ulong fromAddressulong toAddress)
446         {
447             OsCopyMemoryPage(fromAddresstoAddresspageSize);
448         }
449         public nothrow ulong GetPageTableEntry(ulong virtualAddress)
450         {
451             byte segmentIndex = 0u;
452             ulong pageAddress = 0u;
453             ushort offset = 0u;
454             ushort addressSpaceNumber = 0u;
455             Protection pageProtection = Protection.notPresent;
456             ulong pteAddress = 0u;
457             return GetPageTableEntry(virtualAddresssegmentIndexpageAddressoffsetaddressSpaceNumberpageProtectionpteAddress);
458         }
459         public nothrow ulong GetPageTableEntry(ulong virtualAddressbyte& segmentIndexulong& pageAddressushort& offsetushort& addressSpaceNumberProtection& pageProtectionulong& pteAddress)
460         {
461             ulong pte = 0u;
462             pageProtection = Protection.notPresent;
463             segmentIndex = GetSegmentIndex(virtualAddress);
464             ushort segmentOffset = MakeSegmentOffset(segmentIndex);
465             ushort pageTableAddressSpaceNumber = 0u;
466             ulong rv = machine.GetRegisters().GetSpecial(Registers.rV);
467             ulong rootPageAddress = 0u;
468             UnpackVirtualTranslationRegisterValue(rvrootPageAddressaddressSpaceNumber);
469             ulong firstRootPageEntryNumber = segmentOffset;
470             ulong lastDirectRootPageEntryNumber = firstRootPageEntryNumber + numDirectEntries - 1u;
471             ulong firstIndirectEntryNumber = lastDirectRootPageEntryNumber + 1u;
472             ulong singleIndirectEntryNumber = lastDirectRootPageEntryNumber + 1u;
473             ulong doubleIndirectEntryNumber = lastDirectRootPageEntryNumber + 2u;
474             ulong tripleIndirectEntryNumber = lastDirectRootPageEntryNumber + 3u;
475             ulong address = virtualAddress & virtualAddressBaseMask;
476             ulong pageNum = firstRootPageEntryNumber + GetPageNumber(address);
477             offset = cast<ushort>(virtualAddress & pageOffsetMask);
478             if (pageNum >= firstRootPageEntryNumber && pageNum <= lastDirectRootPageEntryNumber)
479             {
480                 pteAddress = rootPageAddress + 8u * pageNum;
481                 pte = ReadMemoryULong(pteAddress);
482                 ushort pteAddressSpaceNumber = 0u;
483                 UnpackPageTableEntry(ptepageAddresspteAddressSpaceNumberpageProtection);
484                 if (pageProtection == Protection.notPresent || addressSpaceNumber != pteAddressSpaceNumber)
485                 {
486                     return 0u;
487                 }
488             }
489             else
490             {
491                 pageNum = pageNum - firstIndirectEntryNumber;
492                 ushort digit0 = 0u;
493                 ushort digit1 = 0u;
494                 ushort digit2 = 0u;
495                 ExtractDigitsFromPageNumber(pageNumdigit0digit1digit2);
496                 if (digit2 == 0u && digit1 == 0u)
497                 {
498                     ulong singleIndirectEntryAddress = rootPageAddress + 8u * singleIndirectEntryNumber;
499                     ulong singleIndirectPageTableEntry = ReadMemoryULong(singleIndirectEntryAddress);
500                     ulong singleIndirectPageAddress = 0u;
501                     ushort singleIndirectAddressSpaceNumber = 0u;
502                     Protection singleIndirectProtection = Protection.notPresent;
503                     UnpackPageTableEntry(singleIndirectPageTableEntrysingleIndirectPageAddresssingleIndirectAddressSpaceNumbersingleIndirectProtection);
504                     if (singleIndirectProtection == Protection.notPresent || addressSpaceNumber != singleIndirectAddressSpaceNumber)
505                     {
506                         return 0u;
507                     }
508                     pteAddress = singleIndirectPageAddress + 8u * digit0;
509                     pte = ReadMemoryULong(pteAddress);
510                     ushort pteAddressSpaceNumber = 0u;
511                     UnpackPageTableEntry(ptepageAddresspteAddressSpaceNumberpageProtection);
512                     if (pageProtection == Protection.notPresent || addressSpaceNumber != pteAddressSpaceNumber)
513                     {
514                         return 0u;
515                     }
516                 }
517                 else if (digit2 == 0u && digit1 > 0u)
518                 {
519                     ulong doubleIndirectEntryAddress = rootPageAddress + 8u * doubleIndirectEntryNumber;
520                     ulong doubleIndirectPageTableEntry = ReadMemoryULong(doubleIndirectEntryAddress);
521                     ulong doubleIndirectPageAddress = 0u;
522                     ushort doubleIndirectAddressSpaceNumber = 0u;
523                     Protection doubleIndirectProtection = Protection.notPresent;
524                     UnpackPageTableEntry(doubleIndirectPageTableEntrydoubleIndirectPageAddressdoubleIndirectAddressSpaceNumberdoubleIndirectProtection);
525                     if (doubleIndirectProtection == Protection.notPresent || addressSpaceNumber != doubleIndirectAddressSpaceNumber)
526                     {
527                         return 0u;
528                     }
529                     ulong singleIndirectEntryAddress = doubleIndirectPageAddress + 8u * digit1;
530                     ulong singleIndirectPageTableEntry = ReadMemoryULong(singleIndirectEntryAddress);
531                     ulong singleIndirectPageAddress = 0u;
532                     ushort singleIndirectAddressSpaceNumber = 0u;
533                     Protection singleIndirectProtection = Protection.notPresent;
534                     UnpackPageTableEntry(singleIndirectPageTableEntrysingleIndirectPageAddresssingleIndirectAddressSpaceNumbersingleIndirectProtection);
535                     if (singleIndirectProtection == Protection.notPresent || addressSpaceNumber != singleIndirectAddressSpaceNumber)
536                     {
537                         return 0u;
538                     }
539                     pteAddress = singleIndirectPageAddress + 8u * digit0;
540                     pte = ReadMemoryULong(pteAddress);
541                     ushort pteAddressSpaceNumber = 0u;
542                     UnpackPageTableEntry(ptepageAddresspteAddressSpaceNumberpageProtection);
543                     if (pageProtection == Protection.notPresent || addressSpaceNumber != pteAddressSpaceNumber)
544                     {
545                         return 0u;
546                     }
547                 }
548                 else if (digit2 >= 0u)
549                 {
550                     ulong tripleIndirectEntryAddress = rootPageAddress + 8u * tripleIndirectEntryNumber;
551                     ulong tripleIndirectPageTableEntry = ReadMemoryULong(tripleIndirectEntryAddress);
552                     ulong tripleIndirectPageAddress = 0u;
553                     ushort tripleIndirectAddressSpaceNumber = 0u;
554                     Protection tripleIndirectProtection = Protection.notPresent;
555                     UnpackPageTableEntry(tripleIndirectPageTableEntrytripleIndirectPageAddresstripleIndirectAddressSpaceNumbertripleIndirectProtection);
556                     if (tripleIndirectProtection == Protection.notPresent || addressSpaceNumber != tripleIndirectAddressSpaceNumber)
557                     {
558                         return 0u;
559                     }
560                     ulong doubleIndirectEntryAddress = tripleIndirectPageAddress + 8u * digit2;
561                     ulong doubleIndirectPageTableEntry = ReadMemoryULong(doubleIndirectEntryAddress);
562                     ulong doubleIndirectPageAddress = 0u;
563                     ushort doubleIndirectAddressSpaceNumber = 0u;
564                     Protection doubleIndirectProtection = Protection.notPresent;
565                     UnpackPageTableEntry(doubleIndirectPageTableEntrydoubleIndirectPageAddressdoubleIndirectAddressSpaceNumberdoubleIndirectProtection);
566                     if (doubleIndirectProtection == Protection.notPresent || addressSpaceNumber != doubleIndirectAddressSpaceNumber)
567                     {
568                         return 0u;
569                     }
570                     ulong singleIndirectEntryAddress = doubleIndirectPageAddress + 8u * digit1;
571                     ulong singleIndirectPageTableEntry = ReadMemoryULong(singleIndirectEntryAddress);
572                     ulong singleIndirectPageAddress = 0u;
573                     ushort singleIndirectAddressSpaceNumber = 0u;
574                     Protection singleIndirectProtection = Protection.notPresent;
575                     UnpackPageTableEntry(singleIndirectPageTableEntrysingleIndirectPageAddresssingleIndirectAddressSpaceNumbersingleIndirectProtection);
576                     if (singleIndirectProtection == Protection.notPresent || addressSpaceNumber != singleIndirectAddressSpaceNumber)
577                     {
578                         return 0u;
579                     }
580                     pteAddress = singleIndirectPageAddress + 8u * digit0;
581                     pte = ReadMemoryULong(pteAddress);
582                     ushort pteAddressSpaceNumber = 0u;
583                     UnpackPageTableEntry(ptepageAddresspteAddressSpaceNumberpageProtection);
584                     if (pageProtection == Protection.notPresent || addressSpaceNumber != pteAddressSpaceNumber)
585                     {
586                         return 0u;
587                     }
588                 }
589             }
590             return pte;
591         }
592         public inline nothrow AddressTranslationCache& GetTranslationCache(ushort addressSpaceNumber)
593         {
594             if (addressSpaceNumber < numDirectTranslationCaches)
595             {
596                 return directTranslationCaches[addressSpaceNumber];
597             }
598             else
599             {
600                 AddressTranslationCache* cache = mappedTranslationCaches[addressSpaceNumber];
601                 if (cache != null)
602                 {
603                     return *cache;
604                 }
605                 else
606                 {
607                     cache = new AddressTranslationCache();
608                     mappedTranslationCaches[addressSpaceNumber] = cache;
609                     return *cache;
610                 }
611             }
612         }
613         public nothrow void ClearTranslationCache(ushort addressSpaceNumber)
614         {
615             if (!UseTranslationCache()) return;
616             AddressTranslationCache& cache = GetTranslationCache(addressSpaceNumber);
617             cache.Clear();
618         }
619         public nothrow void DisposeTranslationCache(ushort addressSpaceNumber)
620         {
621             if (!UseTranslationCache()) return;
622             if (addressSpaceNumber < numDirectTranslationCaches)
623             {
624                 directTranslationCaches[addressSpaceNumber].Clear();
625             }
626             else
627             {
628                 AddressTranslationCache* cache = mappedTranslationCaches[addressSpaceNumber];
629                 if (cache != null)
630                 {
631                     delete cache;
632                     mappedTranslationCaches[addressSpaceNumber] = null;
633                 }
634             }
635         }
636         public nothrow bool GetAddressFromTranslationCache(ulong virtualAddressushort& addressSpaceNumberulong& pageAddressushort& offsetint& entryIndexulong& sourcePageNumber)
637         {
638             ulong rv = machine.GetRegisters().GetSpecial(Registers.rV);
639             ulong rootPageAddress = 0u;
640             addressSpaceNumber = 0u;
641             UnpackVirtualTranslationRegisterValue(rvrootPageAddressaddressSpaceNumber);
642             offset = cast<ushort>(virtualAddress & pageOffsetMask);
643             AddressTranslationCache& cache = GetTranslationCache(addressSpaceNumber);
644             pageAddress = cache.GetEntry(virtualAddressentryIndexsourcePageNumber);
645             if (pageAddress == invalidAddress)
646             {
647                 pageAddress = 0u;
648                 addressSpaceNumber = 0u;
649                 return false;
650             }
651             else
652             {
653                 return true;
654             }
655         }
656         public inline nothrow void SetAddressToTranslationCache(ushort addressSpaceNumberulong pageAddressint entryIndexulong sourcePageNumber)
657         {
658             AddressTranslationCache& cache = GetTranslationCache(addressSpaceNumber);
659             cache.SetEntry(entryIndexsourcePageNumberpageAddress);
660         }
661         public nothrow ulong TranslateAddress(ulong virtualAddressProtection accessbool pageFault)
662         {
663             ulong pageAddress = 0u;
664             ushort offset = 0u;
665             int entryIndex = 0;
666             ulong sourcePageNumber = 0u;
667             ushort addressSpaceNumber = 0u;
668             if (UseTranslationCache())
669             {
670                 bool foundFromCache = GetAddressFromTranslationCache(virtualAddressaddressSpaceNumberpageAddressoffsetentryIndexsourcePageNumber);
671                 if (foundFromCache)
672                 {
673                     return pageAddress + offset;
674                 }
675             }
676             if (CheckSecurityViolation(virtualAddress))
677             {
678                 return invalidAddress;
679             }
680             byte segmentIndex = 0u;
681             Protection pageProtection = Protection.notPresent;
682             ulong pteAddress = 0u;
683             ulong pte = GetPageTableEntry(virtualAddresssegmentIndexpageAddressoffsetaddressSpaceNumberpageProtectionpteAddress);
684             if (pte == 0 && virtualAddress > stackSegmentBaseAddress && virtualAddress < kernelBaseAddress)
685             {
686                 ulong maxStackSize = GetMaxStackSize(addressSpaceNumber);
687                 ulong requiredStackSize = ((virtualAddress - stackSegmentBaseAddress - 1u) / pageSize + 1u) * pageSize;
688                 if (requiredStackSize <= maxStackSize)
689                 {
690                     bool grown = GrowStack(addressSpaceNumber);
691                     while (grown)
692                     {
693                         pte = GetPageTableEntry(virtualAddresssegmentIndexpageAddressoffsetaddressSpaceNumberpageProtectionpteAddress);
694                         if (pte == 0)
695                         {
696                             grown = GrowStack(addressSpaceNumber);
697                         }
698                         else
699                         {
700                             break;
701                         }
702                     }
703                     if (pte == 0)
704                     {
705                         if (pageFault)
706                         {
707                             PageFault(virtualAddresspageProtectionaccess);
708                         }
709                         return invalidAddress;
710                     }
711                 }
712                 else
713                 {
714                     if (pageFault)
715                     {
716                         PageFault(virtualAddresspageProtectionaccess);
717                     }
718                     return invalidAddress;
719                 }
720             }
721             else if (pte != 0u && pageProtection == Protection.copyOnWrite && (access & Protection.write) != 0u)
722             {
723                 ulong newPageAddress = AllocatePage();
724                 CopyPage(pageAddressnewPageAddress);
725                 FreePage(pageAddress);
726                 pageAddress = newPageAddress;
727                 pte = MakePageTableEntry(pageAddressaddressSpaceNumbercast<Protection>(Protection.read | Protection.write));
728                 WriteMemoryULong(pteAddresspte);
729             }
730             else if (pte == 0u || (pageProtection & access) != access)
731             {
732                 if (pageFault)
733                 {
734                     PageFault(virtualAddresspageProtectionaccess);
735                 }
736                 return invalidAddress;
737             }
738             if (UseTranslationCache())
739             {
740                 SetAddressToTranslationCache(addressSpaceNumberpageAddressentryIndexsourcePageNumber);
741             }
742             ulong physicalAddress = pageAddress + offset;
743             return physicalAddress;
744         }
745         public nothrow byte ReadByte(ulong virtualAddressProtection access)
746         {
747             return ReadByte(virtualAddressaccesstrue);
748         }
749         public nothrow byte ReadByte(ulong virtualAddressProtection accessbool pageFault)
750         {
751             ulong address = TranslateAddress(virtualAddressaccesspageFault);
752             if (address != invalidAddress)
753             {
754                 return ReadMemoryByte(address);
755             }
756             else
757             {
758                 return 0u;
759             }
760         }
761         public nothrow void WriteByte(ulong virtualAddressbyte bProtection access)
762         {
763             WriteByte(virtualAddressbaccesstrue);
764         }
765         public nothrow void WriteByte(ulong virtualAddressbyte bProtection accessbool pageFault)
766         {
767             ulong address = TranslateAddress(virtualAddressaccesspageFault);
768             if (address != invalidAddress)
769             {
770                 WriteMemoryByte(addressb);
771             }
772         }
773         public nothrow ushort ReadUShort(ulong virtualAddressProtection access)
774         {
775             return ReadUShort(virtualAddressaccesstrue);
776         }
777         public nothrow ushort ReadUShort(ulong virtualAddressProtection accessbool pageFault)
778         {
779             ulong address = TranslateAddress(virtualAddressaccesspageFault);
780             if (address != invalidAddress)
781             {
782                 return ReadMemoryUShort(address);
783             }
784             else
785             {
786                 return 0u;
787             }
788         }
789         public nothrow void WriteUShort(ulong virtualAddressushort uProtection access)
790         {
791             WriteUShort(virtualAddressuaccesstrue);
792         }
793         public nothrow void WriteUShort(ulong virtualAddressushort uProtection accessbool pageFault)
794         {
795             ulong address = TranslateAddress(virtualAddressaccesspageFault);
796             if (address != invalidAddress)
797             {
798                 WriteMemoryUShort(addressu);
799             }
800         }
801         public nothrow uint ReadUInt(ulong virtualAddressProtection access)
802         {
803             return ReadUInt(virtualAddressaccesstrue);
804         }
805         public nothrow uint ReadUInt(ulong virtualAddressProtection accessbool pageFault)
806         {
807             ulong address = TranslateAddress(virtualAddressaccesspageFault);
808             if (address != invalidAddress)
809             {
810                 return ReadMemoryUInt(address);
811             }
812             else
813             {
814                 return 0u;
815             }
816         }
817         public nothrow void WriteUInt(ulong virtualAddressuint uProtection access)
818         {
819             WriteUInt(virtualAddressuaccesstrue);
820         }
821         public nothrow void WriteUInt(ulong virtualAddressuint uProtection accessbool pageFault)
822         {
823             ulong address = TranslateAddress(virtualAddressaccesspageFault);
824             if (address != invalidAddress)
825             {
826                 WriteMemoryUInt(addressu);
827             }
828         }
829         public nothrow ulong ReadULong(ulong virtualAddressProtection access)
830         {
831             return ReadULong(virtualAddressaccesstrue);
832         }
833         public nothrow ulong ReadULong(ulong virtualAddressProtection accessbool pageFault)
834         {
835             ulong address = TranslateAddress(virtualAddressaccesspageFault);
836             if (address != invalidAddress)
837             {
838                 return ReadMemoryULong(address);
839             }
840             else
841             {
842                 return 0u;
843             }
844         }
845         public nothrow void WriteULong(ulong virtualAddressulong uProtection access)
846         {
847             WriteULong(virtualAddressuaccesstrue);
848         }
849         public nothrow void WriteULong(ulong virtualAddressulong uProtection accessbool pageFault)
850         {
851             ulong address = TranslateAddress(virtualAddressaccesspageFault);
852             if (address != invalidAddress)
853             {
854                 WriteMemoryULong(addressu);
855             }
856         }
857         private nothrow void PageFault(ulong virtualAddressProtection pageProtectionProtection access)
858         {
859             InvokePageFault(machine.GetRegisters()virtualAddresspageProtectionaccess);
860         }
861         private nothrow bool CheckSecurityViolation(ulong virtualAddress)
862         {
863             Registers& regs = machine.GetRegisters();
864             if ((virtualAddress & kernelBaseAddress) != 0u && !IsProcessorInKernelMode(regs))
865             {
866                 SetSecurityViolation(regsvirtualAddress);
867                 return true;
868             }
869             return false;
870         }
871         private HashMap<ulongPageFrame*> pageFrameMap;
872         private PageFrame* freePageFrameList;
873         private Machine& machine;
874         private AddressTranslationCache[16] directTranslationCaches;
875         private HashMap<ushortAddressTranslationCache*> mappedTranslationCaches;
876     }
877 }