《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

263 lines
8.7 KiB

  1. #! /usr/bin/env python
  2. import sys
  3. from optparse import OptionParser
  4. import random
  5. import math
  6. def convert(size):
  7. length = len(size)
  8. lastchar = size[length-1]
  9. if (lastchar == 'k') or (lastchar == 'K'):
  10. m = 1024
  11. nsize = int(size[0:length-1]) * m
  12. elif (lastchar == 'm') or (lastchar == 'M'):
  13. m = 1024*1024
  14. nsize = int(size[0:length-1]) * m
  15. elif (lastchar == 'g') or (lastchar == 'G'):
  16. m = 1024*1024*1024
  17. nsize = int(size[0:length-1]) * m
  18. else:
  19. nsize = int(size)
  20. return nsize
  21. def roundup(size):
  22. value = 1.0
  23. while value < size:
  24. value = value * 2.0
  25. return value
  26. class OS:
  27. def __init__(self):
  28. # 4k phys memory (128 pages)
  29. self.pageSize = 32
  30. self.physPages = 128
  31. self.physMem = self.pageSize * self.physPages
  32. self.vaPages = 1024
  33. self.vaSize = self.pageSize * self.vaPages
  34. self.pteSize = 1
  35. self.pageBits = 5 # log of page size
  36. # os tracks
  37. self.usedPages = []
  38. self.usedPagesCount = 0
  39. self.maxPageCount = self.physMem / self.pageSize
  40. # no pages used (yet)
  41. for i in range(0, self.maxPageCount):
  42. self.usedPages.append(0)
  43. # set contents of memory to 0, too
  44. self.memory = []
  45. for i in range(0, self.physMem):
  46. self.memory.append(0)
  47. # associative array of pdbr's (indexed by PID)
  48. self.pdbr = {}
  49. # mask is 11111 00000 00000 --> 0111 1100 0000 0000
  50. self.PDE_MASK = 0x7c00
  51. self.PDE_SHIFT = 10
  52. # 00000 11111 00000 -> 000 0011 1110 0000
  53. self.PTE_MASK = 0x03e0
  54. self.PTE_SHIFT = 5
  55. self.VPN_MASK = self.PDE_MASK | self.PTE_MASK
  56. self.VPN_SHIFT = self.PTE_SHIFT
  57. # grabs the last five bits of a virtual address
  58. self.OFFSET_MASK = 0x1f
  59. def findFree(self):
  60. assert(self.usedPagesCount < self.maxPageCount)
  61. look = int(random.random() * self.maxPageCount)
  62. while self.usedPages[look] == 1:
  63. look = int(random.random() * self.maxPageCount)
  64. self.usedPagesCount = self.usedPagesCount + 1
  65. self.usedPages[look] = 1
  66. return look
  67. def initPageDir(self, whichPage):
  68. whichByte = whichPage << self.pageBits
  69. for i in range(whichByte, whichByte + self.pageSize):
  70. self.memory[i] = 0x7f
  71. def initPageTablePage(self, whichPage):
  72. self.initPageDir(whichPage)
  73. def getPageTableEntry(self, virtualAddr, ptePage, printStuff):
  74. pteBits = (virtualAddr & self.PTE_MASK) >> self.PTE_SHIFT
  75. pteAddr = (ptePage << self.pageBits) | pteBits
  76. pte = self.memory[pteAddr]
  77. valid = (pte & 0x80) >> 7
  78. pfn = (pte & 0x7f)
  79. if printStuff == True:
  80. print ' --> pte index:0x%x pte contents:(valid %d, pfn 0x%02x)' % (pteBits, valid, pfn)
  81. return (valid, pfn, pteAddr)
  82. def getPageDirEntry(self, pid, virtualAddr, printStuff):
  83. pageDir = self.pdbr[pid]
  84. pdeBits = (virtualAddr & self.PDE_MASK) >> self.PDE_SHIFT
  85. pdeAddr = (pageDir << self.pageBits) | pdeBits
  86. pde = self.memory[pdeAddr]
  87. valid = (pde & 0x80) >> 7
  88. ptPtr = (pde & 0x7f)
  89. if printStuff == True:
  90. print ' --> pde index:0x%x pde contents:(valid %d, pfn 0x%02x)' % (pdeBits, valid, ptPtr)
  91. return (valid, ptPtr, pdeAddr)
  92. def setPageTableEntry(self, pteAddr, physicalPage):
  93. self.memory[pteAddr] = 0x80 | physicalPage
  94. def setPageDirEntry(self, pdeAddr, physicalPage):
  95. self.memory[pdeAddr] = 0x80 | physicalPage
  96. def allocVirtualPage(self, pid, virtualPage, physicalPage):
  97. # make it into a virtual address, as everything uses this (and not VPN)
  98. virtualAddr = virtualPage << self.pageBits
  99. (valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, False)
  100. if valid == 0:
  101. # must allocate a page of the page table now, and have the PD point to it
  102. assert(ptPtr == 127)
  103. ptePage = self.findFree()
  104. self.setPageDirEntry(pdeAddr, ptePage)
  105. self.initPageTablePage(ptePage)
  106. else:
  107. # otherwise, just extract page number of page table page
  108. ptePage = ptPtr
  109. # now, look up page table entry too, and mark it valid and fill in translation
  110. (valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, False)
  111. assert(valid == 0)
  112. assert(pfn == 127)
  113. self.setPageTableEntry(pteAddr, physicalPage)
  114. # -2 -> PTE fault, -1 means PDE fault
  115. def translate(self, pid, virtualAddr):
  116. (valid, ptPtr, pdeAddr) = self.getPageDirEntry(pid, virtualAddr, True)
  117. if valid == 1:
  118. ptePage = ptPtr
  119. (valid, pfn, pteAddr) = self.getPageTableEntry(virtualAddr, ptePage, True)
  120. if valid == 1:
  121. offset = (virtualAddr & self.OFFSET_MASK)
  122. paddr = (pfn << self.pageBits) | offset
  123. # print ' --> pfn: %02x offset: %x' % (pfn, offset)
  124. return paddr
  125. else:
  126. return -2
  127. return -1
  128. def fillPage(self, whichPage):
  129. for j in range(0, self.pageSize):
  130. self.memory[(whichPage * self.pageSize) + j] = int(random.random() * 31)
  131. def procAlloc(self, pid, numPages):
  132. # need a PDBR: find one somewhere in memory
  133. pageDir = self.findFree()
  134. # print '**ALLOCATE** page dir', pageDir
  135. self.pdbr[pid] = pageDir
  136. self.initPageDir(pageDir)
  137. used = {}
  138. for vp in range(0, self.vaPages):
  139. used[vp] = 0
  140. allocatedVPs = []
  141. for vp in range(0, numPages):
  142. vp = int(random.random() * self.vaPages)
  143. while used[vp] == 1:
  144. vp = int(random.random() * self.vaPages)
  145. assert(used[vp] == 0)
  146. used[vp] = 1
  147. allocatedVPs.append(vp)
  148. pp = self.findFree()
  149. # print '**ALLOCATE** page', pp
  150. # print ' trying to map vp:%08x to pp:%08x' % (vp, pp)
  151. self.allocVirtualPage(pid, vp, pp)
  152. self.fillPage(pp)
  153. return allocatedVPs
  154. def dumpPage(self, whichPage):
  155. i = whichPage
  156. for j in range(0, self.pageSize):
  157. print self.memory[(i * self.pageSize) + j],
  158. print ''
  159. def memoryDump(self):
  160. for i in range(0, self.physMem / self.pageSize):
  161. print 'page %3d:' % i,
  162. for j in range(0, self.pageSize):
  163. print '%02x' % self.memory[(i * self.pageSize) + j],
  164. print ''
  165. def getPDBR(self, pid):
  166. return self.pdbr[pid]
  167. def getValue(self, addr):
  168. return self.memory[addr]
  169. # allocate some processes in memory
  170. # allocate some multi-level page tables in memory
  171. # make a bit of a mystery:
  172. # can examine PDBR (PFN of current proc's page directory)
  173. # can examine contents of any page
  174. # fill pages with values too
  175. # ask: when given
  176. # LOAD VA, R1
  177. # what will final value will be loaded into R1?
  178. #
  179. # main program
  180. #
  181. parser = OptionParser()
  182. parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
  183. parser.add_option('-a', '--allocated', default=64, help='number of virtual pages allocated',
  184. action='store', type='int', dest='allocated')
  185. parser.add_option('-n', '--addresses', default=10, help='number of virtual addresses to generate',
  186. action='store', type='int', dest='num')
  187. parser.add_option('-c', '--solve', help='compute answers for me', action='store_true', default=False, dest='solve')
  188. (options, args) = parser.parse_args()
  189. print 'ARG seed', options.seed
  190. print 'ARG allocated', options.allocated
  191. print 'ARG num', options.num
  192. print ""
  193. random.seed(options.seed)
  194. # do the work now
  195. os = OS()
  196. used = os.procAlloc(1, options.allocated)
  197. os.memoryDump()
  198. print '\nPDBR:', os.getPDBR(1), ' (decimal) [This means the page directory is held in this page]\n'
  199. for i in range(0, options.num):
  200. if (random.random() * 100) > 50.0 or i >= len(used):
  201. vaddr = int(random.random() * 1024 * 32)
  202. else:
  203. vaddr = (used[i] << 5) | int(random.random() * 32)
  204. if options.solve == True:
  205. print 'Virtual Address %04x:' % vaddr
  206. r = os.translate(1, vaddr)
  207. if r > -1:
  208. print ' --> Translates to Physical Address 0x%03x --> Value: %02x' % (r, os.getValue(r))
  209. elif r == -1:
  210. print ' --> Fault (page directory entry not valid)'
  211. else:
  212. print ' --> Fault (page table entry not valid)'
  213. else:
  214. print 'Virtual Address %04x: Translates To What Physical Address (And Fetches what Value)? Or Fault?' % vaddr
  215. print ''
  216. exit(0)