os_kernel_lab/related_info/ostep/ostep5-paging-multilevel-translate.py
2015-03-15 16:54:19 +08:00

264 lines
8.7 KiB
Python
Executable File

#! /usr/bin/env python
import sys
from optparse import OptionParser
import random
import math
def convert(size):
length = len(size)
lastchar = size[length-1]
if (lastchar == 'k') or (lastchar == 'K'):
m = 1024
nsize = int(size[0:length-1]) * m
elif (lastchar == 'm') or (lastchar == 'M'):
m = 1024*1024
nsize = int(size[0:length-1]) * m
elif (lastchar == 'g') or (lastchar == 'G'):
m = 1024*1024*1024
nsize = int(size[0:length-1]) * m
else:
nsize = int(size)
return nsize
def roundup(size):
value = 1.0
while value < size:
value = value * 2.0
return value
class OS:
def __init__(self):
# 4k phys memory (128 pages)
self.pageSize = 32
self.physPages = 128
self.physMem = self.pageSize * self.physPages
self.vaPages = 1024
self.vaSize = self.pageSize * self.vaPages
self.pteSize = 1
self.pageBits = 5 # log of page size
# os tracks
self.usedPages = []
self.usedPagesCount = 0
self.maxPageCount = self.physMem / self.pageSize
# no pages used (yet)
for i in range(0, self.maxPageCount):
self.usedPages.append(0)
# set contents of memory to 0, too
self.memory = []
for i in range(0, self.physMem):
self.memory.append(0)
# associative array of pdbr's (indexed by PID)
self.pdbr = {}
# mask is 11111 00000 00000 --> 0111 1100 0000 0000
self.PDE_MASK = 0x7c00
self.PDE_SHIFT = 10
# 00000 11111 00000 -> 000 0011 1110 0000
self.PTE_MASK = 0x03e0
self.PTE_SHIFT = 5
self.VPN_MASK = self.PDE_MASK | self.PTE_MASK
self.VPN_SHIFT = self.PTE_SHIFT
# grabs the last five bits of a virtual address
self.OFFSET_MASK = 0x1f
def findFree(self):
assert(self.usedPagesCount < self.maxPageCount)
look = int(random.random() * self.maxPageCount)
while self.usedPages[look] == 1:
look = int(random.random() * self.maxPageCount)
self.usedPagesCount = self.usedPagesCount + 1
self.usedPages[look] = 1
return look
def initPageDir(self, whichPage):
whichByte = whichPage << self.pageBits
for i in range(whichByte, whichByte + self.pageSize):
self.memory[i] = 0x7f
def initPageTablePage(self, whichPage):
self.initPageDir(whichPage)
def getPageTableEntry(self, virtualAddr, ptePage, printStuff):
pteBits = (virtualAddr & self.PTE_MASK) >> self.PTE_SHIFT
pteAddr = (ptePage << self.pageBits) | pteBits
pte = self.memory[pteAddr]
valid = (pte & 0x80) >> 7
pfn = (pte & 0x7f)
if printStuff == True:
print ' --> pte index:0x%x pte contents:(valid %d, pfn 0x%02x)' % (pteBits, valid, pfn)
return (valid, pfn, pteAddr)
def getPageDirEntry(self, pid, virtualAddr, printStuff):
pageDir = self.pdbr[pid]
pdeBits = (virtualAddr & self.PDE_MASK) >> self.PDE_SHIFT
pdeAddr = (pageDir << self.pageBits) | pdeBits
pde = self.memory[pdeAddr]
valid = (pde & 0x80) >> 7
ptPtr = (pde & 0x7f)
if printStuff == True:
print ' --> pde index:0x%x pde contents:(valid %d, pfn 0x%02x)' % (pdeBits, valid, ptPtr)
return (valid, ptPtr, pdeAddr)
def setPageTableEntry(self, pteAddr, physicalPage):
self.memory[pteAddr] = 0x80 | physicalPage
def setPageDirEntry(self, pdeAddr, physicalPage):
self.memory[pdeAddr] = 0x80 | physicalPage
def allocVirtualPage(self, pid, virtualPage, physicalPage):
# make it into a virtual address, as everything uses this (and not VPN)
virtualAddr = virtualPage << self.pageBits
(valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, False)
if valid == 0:
# must allocate a page of the page table now, and have the PD point to it
assert(ptPtr == 127)
ptePage = self.findFree()
self.setPageDirEntry(pdeAddr, ptePage)
self.initPageTablePage(ptePage)
else:
# otherwise, just extract page number of page table page
ptePage = ptPtr
# now, look up page table entry too, and mark it valid and fill in translation
(valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, False)
assert(valid == 0)
assert(pfn == 127)
self.setPageTableEntry(pteAddr, physicalPage)
# -2 -> PTE fault, -1 means PDE fault
def translate(self, pid, virtualAddr):
(valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, True)
if valid == 1:
ptePage = ptPtr
(valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, True)
if valid == 1:
offset = (virtualAddr & self.OFFSET_MASK)
paddr = (pfn << self.pageBits) | offset
# print ' --> pfn: %02x offset: %x' % (pfn, offset)
return paddr
else:
return -2
return -1
def fillPage(self, whichPage):
for j in range(0, self.pageSize):
self.memory[(whichPage * self.pageSize) + j] = int(random.random() * 31)
def procAlloc(self, pid, numPages):
# need a PDBR: find one somewhere in memory
pageDir = self.findFree()
# print '**ALLOCATE** page dir', pageDir
self.pdbr[pid] = pageDir
self.initPageDir(pageDir)
used = {}
for vp in range(0, self.vaPages):
used[vp] = 0
allocatedVPs = []
for vp in range(0, numPages):
vp = int(random.random() * self.vaPages)
while used[vp] == 1:
vp = int(random.random() * self.vaPages)
assert(used[vp] == 0)
used[vp] = 1
allocatedVPs.append(vp)
pp = self.findFree()
# print '**ALLOCATE** page', pp
# print ' trying to map vp:%08x to pp:%08x' % (vp, pp)
self.allocVirtualPage(pid, vp, pp)
self.fillPage(pp)
return allocatedVPs
def dumpPage(self, whichPage):
i = whichPage
for j in range(0, self.pageSize):
print self.memory[(i * self.pageSize) + j],
print ''
def memoryDump(self):
for i in range(0, self.physMem / self.pageSize):
print 'page %3d:' % i,
for j in range(0, self.pageSize):
print '%02x' % self.memory[(i * self.pageSize) + j],
print ''
def getPDBR(self, pid):
return self.pdbr[pid]
def getValue(self, addr):
return self.memory[addr]
# allocate some processes in memory
# allocate some multi-level page tables in memory
# make a bit of a mystery:
# can examine PDBR (PFN of current proc's page directory)
# can examine contents of any page
# fill pages with values too
# ask: when given
# LOAD VA, R1
# what will final value will be loaded into R1?
#
# main program
#
parser = OptionParser()
parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
parser.add_option('-a', '--allocated', default=64, help='number of virtual pages allocated',
action='store', type='int', dest='allocated')
parser.add_option('-n', '--addresses', default=10, help='number of virtual addresses to generate',
action='store', type='int', dest='num')
parser.add_option('-c', '--solve', help='compute answers for me', action='store_true', default=False, dest='solve')
(options, args) = parser.parse_args()
print 'ARG seed', options.seed
print 'ARG allocated', options.allocated
print 'ARG num', options.num
print ""
random.seed(options.seed)
# do the work now
os = OS()
used = os.procAlloc(1, options.allocated)
os.memoryDump()
print '\nPDBR:', os.getPDBR(1), ' (decimal) [This means the page directory is held in this page]\n'
for i in range(0, options.num):
if (random.random() * 100) > 50.0 or i >= len(used):
vaddr = int(random.random() * 1024 * 32)
else:
vaddr = (used[i] << 5) | int(random.random() * 32)
if options.solve == True:
print 'Virtual Address %04x:' % vaddr
r = os.translate(1, vaddr)
if r > -1:
print ' --> Translates to Physical Address 0x%03x --> Value: %02x' % (r, os.getValue(r))
elif r == -1:
print ' --> Fault (page directory entry not valid)'
else:
print ' --> Fault (page table entry not valid)'
else:
print 'Virtual Address %04x: Translates To What Physical Address (And Fetches what Value)? Or Fault?' % vaddr
print ''
exit(0)