home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / OSProject / p5 / FileStuff.c < prev    next >
Text File  |  2007-09-19  |  36KB  |  866 lines

  1. -----------------------------  DiskDriver  ---------------------------------
  2.  
  3.   const
  4.     DISK_STATUS_BUSY                               = 0x00000000
  5.     DISK_STATUS_OPERATION_COMPLETED_OK             = 0x00000001
  6.     DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1   = 0x00000002
  7.     DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2   = 0x00000003
  8.     DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3   = 0x00000004
  9.     DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4   = 0x00000005
  10.     DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5   = 0x00000006
  11.  
  12.     DISK_READ_COMMAND  = 0x00000001
  13.     DISK_WRITE_COMMAND = 0x00000002
  14.  
  15.   behavior DiskDriver
  16.     --
  17.     -- There is only one instance of this class.  It provides "read" and "write"
  18.     -- methods to transfer data from and to the disk.
  19.     --
  20.     -- In this implementation, all I/O is synchronous.  These methods perform
  21.     -- busy-waiting until the disk operation has completed.
  22.  
  23.       ----------  DiskDriver . Init  ----------
  24.  
  25.       method Init ()
  26.           print ("Initializing Disk Driver...\n")
  27.           DISK_STATUS_WORD_ADDRESS = 0x00FFFF08 asPtrTo int
  28.           DISK_COMMAND_WORD_ADDRESS = 0x00FFFF08 asPtrTo int
  29.           DISK_MEMORY_ADDRESS_REGISTER = 0x00FFFF0C asPtrTo int
  30.           DISK_SECTOR_NUMBER_REGISTER = 0x00FFFF10 asPtrTo int
  31.           DISK_SECTOR_COUNT_REGISTER = 0x00FFFF14 asPtrTo int
  32.           semToSignalOnCompletion = null
  33.           semUsedInSynchMethods = new Semaphore
  34.           semUsedInSynchMethods.Init (0)
  35.           diskBusy = new Mutex
  36.           diskBusy.Init ()
  37.         endMethod
  38.  
  39.       ----------  DiskDriver . SynchReadSector  ----------
  40.  
  41.       method SynchReadSector  (sectorAddr, numberOfSectors, memoryAddr: int)
  42.         --
  43.         -- This method reads "numberOfSectors" sectors (of PAGE_SIZE bytes each)
  44.         -- from the disk and places the data in memory, starting at "memoryAddr".
  45.         -- It waits until the I/O is complete before returning.
  46.         --
  47.         -- If there is a (simulated) disk hardware failure, then this routine
  48.         -- simply tries again in an infinite loop, until it succeeds.
  49.         --
  50.           -- print ("SynchReadSector called\n")
  51.           -- printIntVar ("  sectorAddr", sectorAddr)
  52.           -- printIntVar ("  numberOfSectors", numberOfSectors)
  53.           -- printHexVar ("  memoryAddr", memoryAddr)
  54.           diskBusy.Lock ()
  55.           while true
  56.  
  57.             self.StartReadSector  (sectorAddr, numberOfSectors, memoryAddr,
  58.                                    & semUsedInSynchMethods)
  59.             semUsedInSynchMethods.Down ()
  60.  
  61.             -- Check the return status
  62.             switch * DISK_STATUS_WORD_ADDRESS
  63.               case DISK_STATUS_OPERATION_COMPLETED_OK:
  64.                 diskBusy.Unlock ()
  65.                 return
  66.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1:
  67.                 FatalError ("Disk I/O error in SynchReadSector: Memory addr is not page-aligned or sector count is not positive")
  68.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2:
  69.                 FatalError ("Disk I/O error in SynchReadSector: Attempt to access invalid memory address")
  70.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3:
  71.                 FatalError ("Disk I/O error in SynchReadSector: Bad sectorAddr or sectorCount specifies non-existant sector")
  72.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4:
  73.                 -- This case occurs when there is a hard or soft (simulated)
  74.                 -- hardware error while performing the disk operation.
  75.                 break
  76.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5:
  77.                 FatalError ("Disk I/O error in SynchReadSector: Bad command word")
  78.               default:
  79.                 FatalError ("SynchReadSector: Unexpected status code")
  80.             endSwitch
  81.             -- print ("\n\nIn SynchReadSector: A simulated disk I/O error occurred...\n\n")
  82.           endWhile
  83.  
  84.         endMethod
  85.  
  86.       ----------  DiskDriver . StartReadSector  ----------
  87.  
  88.       method StartReadSector  (sectorAddr, numberOfSectors, memoryAddr: int,
  89.                                whoCares: ptr to Semaphore)
  90.         --
  91.         -- This method reads "numberOfSectors" sectors (of PAGE_SIZE bytes each)
  92.         -- from the disk and places the data in memory, starting at "memoryAddr".
  93.         -- The "whoCares" argument is a Semaphore that we will signal after the
  94.         -- I/O operation is complete; if null no thread will be notified.
  95.         --
  96.           -- print ("StartReadSector called\n")
  97.           -- printIntVar ("  sectorAddr", sectorAddr)
  98.           -- printIntVar ("  numberOfSectors", numberOfSectors)
  99.           -- printHexVar ("  memoryAddr", memoryAddr)
  100.           -- printHexVar ("  whoCares", whoCares asInteger)
  101.  
  102.           -- Save the semaphore
  103.           semToSignalOnCompletion = whoCares
  104.  
  105.           -- Move the parameters to the disk and start the I/O
  106.           * DISK_MEMORY_ADDRESS_REGISTER = memoryAddr
  107.           * DISK_SECTOR_NUMBER_REGISTER = sectorAddr
  108.           * DISK_SECTOR_COUNT_REGISTER = numberOfSectors
  109.           * DISK_COMMAND_WORD_ADDRESS = DISK_READ_COMMAND    -- Starts the I/O
  110.         endMethod
  111.  
  112.       ----------  DiskDriver . SynchWriteSector  ----------
  113.  
  114.       method SynchWriteSector  (sectorAddr, numberOfSectors, memoryAddr: int)
  115.         --
  116.         -- This method writes "numberOfSectors" sectors (of PAGE_SIZE bytes each)
  117.         -- to the disk.  It waits until the I/O is complete before returning.
  118.         --
  119.         -- If there is a (simulated) disk hardware failure, then this routine
  120.         -- simply tries again in an infinite loop, until it succeeds.
  121.         --
  122.           -- print ("SynchWriteSector called\n")
  123.           -- printIntVar ("  sectorAddr", sectorAddr)
  124.           -- printIntVar ("  numberOfSectors", numberOfSectors)
  125.           -- printHexVar ("  memoryAddr", memoryAddr)
  126.           diskBusy.Lock ()
  127.           while true
  128.             self.StartWriteSector  (sectorAddr, numberOfSectors, memoryAddr,
  129.                                     & semUsedInSynchMethods)
  130.             semUsedInSynchMethods.Down ()
  131.  
  132.             -- Check the return status
  133.             switch * DISK_STATUS_WORD_ADDRESS
  134.               case DISK_STATUS_OPERATION_COMPLETED_OK:
  135.                 diskBusy.Unlock ()
  136.                 return
  137.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1:
  138.                 FatalError ("Disk I/O error in SynchWriteSector: Memory addr is not page-aligned or sector count is not positive")
  139.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2:
  140.                 FatalError ("Disk I/O error in SynchWriteSector: Attempt to access invalid memory address")
  141.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3:
  142.                 FatalError ("Disk I/O error in SynchWriteSector: Bad sectorAddr or sectorCount specifies non-existant sector")
  143.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4:
  144.                 -- This case occurs when there is a hard or soft (simulated)
  145.                 -- hardware error while performing the disk operation.
  146.                 break
  147.               case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5:
  148.                 FatalError ("Disk I/O error in SynchWriteSector: Bad command word")
  149.               default:
  150.                 FatalError ("SynchWriteSector: Unexpected status code")
  151.             endSwitch
  152.             -- print ("\n\nIn SynchWriteSector: A simulated disk I/O error occurred...\n\n")
  153.           endWhile
  154.  
  155.         endMethod
  156.  
  157.       ----------  DiskDriver . StartWriteSector  ----------
  158.  
  159.       method StartWriteSector  (sectorAddr, numberOfSectors, memoryAddr: int,
  160.                                 whoCares: ptr to Semaphore)
  161.         --
  162.         -- This method writes "numberOfSectors" sectors (of PAGE_SIZE bytes each)
  163.         -- to the disk.  It returns immediately after starting the I/O.
  164.         --
  165.         -- The "whoCares" argument is a Semaphore that we will signal after the
  166.         -- I/O operation is complete; if null no thread will be notified.
  167.         --
  168.           -- print ("SynchWriteSector called\n")
  169.           -- printIntVar ("  sectorAddr", sectorAddr)
  170.           -- printIntVar ("  numberOfSectors", numberOfSectors)
  171.           -- printHexVar ("  memoryAddr", memoryAddr)
  172.  
  173.           -- Save the semaphore
  174.           semToSignalOnCompletion = whoCares
  175.  
  176.           * DISK_MEMORY_ADDRESS_REGISTER = memoryAddr
  177.           * DISK_SECTOR_NUMBER_REGISTER = sectorAddr
  178.           * DISK_SECTOR_COUNT_REGISTER = numberOfSectors
  179.           * DISK_COMMAND_WORD_ADDRESS = DISK_WRITE_COMMAND    -- Starts the I/O
  180.         endMethod
  181.  
  182.     endBehavior
  183.  
  184. -----------------------------  FileManager  ---------------------------------
  185.  
  186.   behavior FileManager
  187.  
  188.       ----------  FileManager . Init  ----------
  189.  
  190.       method Init ()
  191.         --
  192.         -- This method is called once at kernel startup time to initialize
  193.         -- the one and only "FileManager" object.  It is passed a pointer
  194.         -- to a frame of memory. 
  195.         --
  196.         var i: int
  197.           print ("Initializing File Manager...\n")
  198.           fileManagerLock = new Mutex
  199.           fileManagerLock.Init ()
  200.  
  201.           -- Initialize the FileControlBlock stuff
  202.           fcbFreeList = new List [FileControlBlock]
  203.           anFCBBecameFree = new Condition
  204.           anFCBBecameFree.Init ()
  205.           fcbTable = new array of FileControlBlock
  206.                 { MAX_NUMBER_OF_FILE_CONTROL_BLOCKS of new FileControlBlock }
  207.           for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
  208.             fcbTable[i].fcbID = i
  209.             fcbTable[i].Init()
  210.             fcbFreeList.AddToEnd (&fcbTable[i])
  211.           endFor
  212.  
  213.           -- Initialize the OpenFile stuff
  214.           openFileFreeList = new List [OpenFile]
  215.           anOpenFileBecameFree = new Condition
  216.           anOpenFileBecameFree.Init ()
  217.           openFileTable = new array of OpenFile
  218.                 { MAX_NUMBER_OF_OPEN_FILES of new OpenFile }
  219.           for i = 0 to MAX_NUMBER_OF_OPEN_FILES-1
  220.             openFileTable[i].kind = FILE
  221.             openFileFreeList.AddToEnd (&openFileTable[i])
  222.           endFor
  223.  
  224.           -- Create the special "stdin/stdout" open file
  225.           serialTerminalFile = new OpenFile
  226.           serialTerminalFile.kind = TERMINAL
  227.  
  228.           -- Read in sector 0 from the disk.  This is the
  229.           -- "Stub System" directory page.  We'll just keep this around
  230.           -- forever, for use whenever we want to open a file.
  231.           directoryFrame = frameManager.GetAFrame ()
  232.           diskDriver.SynchReadSector (0,    -- sector to read
  233.                                       1,    -- number of sectors to read
  234.                                       directoryFrame)
  235.         endMethod
  236.  
  237.       ----------  FileManager . Print  ----------
  238.  
  239.       method Print ()
  240.         var i: int
  241.           fileManagerLock.Lock ()           -- Need lock since we touch freeLists
  242.           print ("Here is the FileControlBlock table...\n")
  243.           for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
  244.             print ("  ")
  245.             printInt (i)
  246.             print (":  ")
  247.             fcbTable[i].Print()
  248.           endFor
  249.           print ("Here is the FREE list of FileControlBlocks:\n   ")
  250.           fcbFreeList.ApplyToEach (printFCB)
  251.           nl ()
  252.           print ("Here is the OpenFile table...\n")
  253.           for i = 0 to MAX_NUMBER_OF_OPEN_FILES-1
  254.             print ("  ")
  255.             printInt (i)
  256.             print (":  0x")
  257.             printHex ((& openFileTable[i]) asInteger)
  258.             print (":  ")
  259.             openFileTable[i].Print()
  260.           endFor
  261.           print ("Here is the FREE list of OpenFiles:\n")
  262.           openFileFreeList.ApplyToEach (printOpen)
  263.           fileManagerLock.Unlock ()
  264.         endMethod
  265.  
  266.       ----------  FileManager . Open  ----------
  267.  
  268.       method Open (filename: String) returns ptr to OpenFile
  269.       --
  270.       -- This method is called to open a file.  It returns pointer to
  271.       -- a newly allocated OpenFile.  It will set its "numberOfUsers"
  272.       -- count to 1.
  273.       --
  274.       -- The file must already exist on the disk.  If it cannot be found,
  275.       -- this method returns null.
  276.       --
  277.       -- This method is reentrant, and may block the caller.
  278.       --
  279.           var open: ptr to OpenFile
  280.               fcb: ptr to FileControlBlock
  281.  
  282.           -- First, get an FCB that points to the file.
  283.           -- This will increment fcb.numberOfUsers.
  284.           fcb = fileManager.FindFCB (filename)
  285.           if fcb == null
  286.             return null
  287.           endIf
  288.  
  289.           -- Next, allocate an OpenFile, waiting if necessary.
  290.           fileManagerLock.Lock()
  291.           while openFileFreeList.IsEmpty ()
  292.             anOpenFileBecameFree.Wait (& fileManagerLock)
  293.           endWhile
  294.           open = openFileFreeList.Remove ()
  295.  
  296.           -- Connect it to this FCB and set its "numberOfUsers" count.
  297.           open.fcb = fcb
  298.           open.numberOfUsers = 1
  299.           -- printHexVar ("open.fcb", open.fcb asInteger)
  300.  
  301.           open.currentPos = 0
  302.           -- Release FileManagerLock and return a pointer to the OpenFile object
  303.           fileManagerLock.Unlock()
  304.           return open
  305.         endMethod
  306.  
  307.       ----------  FileManager . FindFCB  ----------
  308.  
  309.       method FindFCB (filename: String) returns ptr to FileControlBlock
  310.       --
  311.       -- This method is called when opening a file.  The file may already be
  312.       -- open; if so we return a pointer to the FCB that describes that
  313.       -- file.  If not, we allocate a new FCB and return a pointer to it.
  314.       --
  315.       -- The file must already exist on the disk.  If it cannot be found,
  316.       -- this method returns null.
  317.       --
  318.       -- The numberOfUsers field in the FCB is incremented.
  319.       --
  320.       -- This implementation is a "dummy" implementation, using the "stub"
  321.       -- file system.  The stub file system has a single directory which
  322.       -- is stored in sector 0.  When the fileManager was initialized, sector
  323.       -- 0 was pre-read, so all we do here is consult it to locate the
  324.       -- the file.  Then we store the relevant info in the FCB.
  325.       --
  326.       -- This method is reentrant, and may block the caller.
  327.       --
  328.           var i, start, numFiles, fileLen, fileNameLen: int
  329.               fcb: ptr to FileControlBlock
  330.               p: ptr to int
  331.           -- print ("Opening a file\n")
  332.  
  333.           -- Begin the search with byte 0 of the directory sector
  334.           p = directoryFrame asPtrTo int
  335.  
  336.           -- Check the magic number
  337.           i = *p
  338.           p = p + 4
  339.           if i != 0x73747562       -- in ASCII this is "stub"
  340.             FatalError ("Magic number in sector 0 of stub file system is bad")
  341.           endIf
  342.  
  343.           -- Get the number of files in the directory
  344.           numFiles = *p
  345.           p = p + 4
  346.           i = *p     -- This is the nextFreeSector; ignore it.
  347.           p = p + 4
  348.  
  349.           -- Run through each directory entry, looking for a match
  350.           while numFiles > 0
  351.             copyUnalignedWord (&start, p)
  352.             p = p + 4
  353.             copyUnalignedWord (&fileLen, p)
  354.             p = p + 4
  355.             copyUnalignedWord (&fileNameLen, p)
  356.             p = p + 4
  357.             if fileNameLen == filename arraySize &&
  358.                   MemoryEqual (p asPtrTo char, &filename[0], fileNameLen)
  359.               break
  360.             endIf
  361.             p = p + fileNameLen
  362.             numFiles = numFiles - 1
  363.           endWhile
  364.  
  365.           -- If we didn't find a matching name, return null
  366.           if numFiles <= 0
  367.             return null
  368.           endIf
  369.  
  370.           fileManagerLock.Lock()
  371.           -- See if there is an FCB for this file; if so return it.
  372.           for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
  373.             fcb = &fcbTable[i]
  374.             if fcb.startingSectorOfFile == start
  375.               fcb.numberOfUsers = fcb.numberOfUsers + 1
  376.               fileManagerLock.Unlock()
  377.               return fcb
  378.             endIf
  379.           endFor
  380.  
  381.           -- Get an unused FCB, waiting until one becomes available
  382.           while fcbFreeList.IsEmpty ()
  383.             anFCBBecameFree.Wait (& fileManagerLock)
  384.           endWhile
  385.           fcb = fcbFreeList.Remove ()
  386.  
  387.           -- Safe to unlock now, since no one else will use this FCB
  388.           fileManagerLock.Unlock()
  389.  
  390.           -- Set the FCB up, and return it.
  391.           fcb.startingSectorOfFile = start
  392.           fcb.sizeOfFileInBytes = fileLen
  393.           fcb.numberOfUsers = 1
  394.           if fcb.relativeSectorInBuffer >= 0 || fcb.bufferIsDirty
  395.             FatalError ("In FileManager.Open: a free FCB appears not to have been closed properly")
  396.           endIf
  397.           return fcb
  398.         endMethod
  399.  
  400.       ----------  FileManager . Close  ----------
  401.       --
  402.       -- This method is called to close an OpenFile.  If there is a pending
  403.       -- write (i.e., the buffer is dirty) then it is written out first.
  404.       --
  405.       -- The "numberOfUsers" for the OpenFile is decremented and, if zero,
  406.       -- the OpenFile is freed.  If the OpenFile is freed, then the
  407.       -- "numberOfUsers" for the FCB is decremented.  If it too is zero, the
  408.       -- FCB is freed.
  409.       --
  410.       method Close (open: ptr to OpenFile)
  411.           var fcb: ptr to FileControlBlock
  412.           if open == & serialTerminalFile
  413.             return
  414.           endIf
  415.           fileManagerLock.Lock()
  416.           fileManager.Flush (open)
  417.           fcb = open.fcb
  418.           open.numberOfUsers = open.numberOfUsers - 1
  419.           if open.numberOfUsers <= 0
  420.             openFileFreeList.AddToEnd (open)
  421.             anOpenFileBecameFree.Signal (& fileManagerLock)
  422.             fcb.numberOfUsers = fcb.numberOfUsers - 1
  423.             if fcb.numberOfUsers <= 0
  424.               fcbFreeList.AddToEnd (fcb)
  425.               anFCBBecameFree.Signal (& fileManagerLock)
  426.             endIf
  427.           endIf
  428.           fileManagerLock.Unlock()
  429.         endMethod
  430.  
  431.       ----------  FileManager . Flush  ----------
  432.  
  433.       method Flush (open: ptr to OpenFile)
  434.         --
  435.         -- This method writes out the buffer, if it is dirty.  This method
  436.         -- assumes the caller already holds the fileManagerLock.
  437.         --
  438.           if open.fcb.bufferIsDirty
  439.             if open.fcb.relativeSectorInBuffer < 0
  440.               FatalError ("FileManager.Flush: buffer is dirty but relativeSectorInBuffer =  -1")
  441.             endIf
  442.             open.fcb.bufferIsDirty = false
  443.             diskDriver.SynchWriteSector (
  444.                        open.fcb.relativeSectorInBuffer+open.fcb.startingSectorOfFile,
  445.                        1,
  446.                        open.fcb.bufferPtr)
  447.           endIf
  448.         endMethod
  449.  
  450.       ----------  FileManager . SynchRead  ----------
  451.  
  452.       method SynchRead (open: ptr to OpenFile, 
  453.                         targetAddr, bytePos, numBytes: int) returns bool
  454.           --
  455.           -- This method reads "numBytes" from this file and stores
  456.           -- them at the address pointed to by "targetAddr".  If everything
  457.           -- was read okay, it returns TRUE; if problems it returns FALSE.
  458.           --
  459.           -- It reads a page at a time into an internal buffer
  460.           -- by calling "diskDriver.SynchReadSector".
  461.           --
  462.           var sector, offset, posInBuffer, bytesToMove: int
  463.               fcb: ptr to FileControlBlock
  464.           -- printHexVar ("SynchRead called  targetAddr", targetAddr)
  465.           -- printIntVar ("                  bytePos", bytePos)
  466.           -- printIntVar ("                  numBytes", numBytes)
  467.           fileManagerLock.Lock()
  468.           if ! open || ! open.fcb || open.fcb.startingSectorOfFile < 0
  469.             FatalError ("FileManager.SynchRead: file not properly opened")
  470.           endIf
  471.           fcb = open.fcb
  472.           while numBytes > 0
  473.             -- At this point targetAddr and numBytes tell what work is left to do.
  474.             -- printHexVar ("NEXT MOVE:\n  targetAddr", targetAddr)
  475.             -- printIntVar ("  numBytes", numBytes)
  476.             -- printHexVar ("          ", numBytes)
  477.             -- printIntVar ("  startingSectorOfFile", fcb.startingSectorOfFile)
  478.             -- printIntVar ("  relativeSectorInBuffer", fcb.relativeSectorInBuffer)
  479.             -- printIntVar ("  bytePos", bytePos)
  480.             -- printHexVar ("         ", bytePos)
  481.             sector = bytePos / PAGE_SIZE
  482.             offset = bytePos % PAGE_SIZE
  483.             -- printIntVar ("  sector", sector)
  484.             -- printIntVar ("  offset", offset)
  485.             -- printHexVar ("        ", offset)
  486.             if fcb.relativeSectorInBuffer != sector
  487.               self.Flush (open)
  488.               -- printIntVar ("  READING SECTOR", sector+startingSectorOfFile)
  489.               diskDriver.SynchReadSector (sector + fcb.startingSectorOfFile,
  490.                                            1,
  491.                                            fcb.bufferPtr)
  492.               fcb.relativeSectorInBuffer = sector
  493.               fcb.bufferIsDirty = false    -- (This is unnecessary since Flush does it)
  494.             endIf
  495.             posInBuffer = fcb.bufferPtr + offset
  496.             bytesToMove = Min (numBytes, PAGE_SIZE - offset)
  497.             -- printHexVar ("  MOVING - targetAddr", targetAddr)
  498.             -- printHexVar ("         - source addr (posInBuffer)", posInBuffer)
  499.             -- printIntVar ("         - bytesToMove", bytesToMove)
  500.             MemoryCopy (targetAddr, posInBuffer, bytesToMove)
  501.             targetAddr = targetAddr + bytesToMove
  502.             bytePos = bytePos + bytesToMove
  503.             numBytes = numBytes - bytesToMove
  504.             -- printHexVar ("  NEW targetAddr", targetAddr)
  505.             -- printIntVar ("  NEW bytePos", bytePos)
  506.             -- printHexVar ("             ", bytePos)
  507.             -- printIntVar ("  NEW numBytes", numBytes)
  508.             -- printHexVar ("              ", numBytes)
  509.           endWhile
  510.           fileManagerLock.Unlock()
  511.           return true
  512.         endMethod
  513.  
  514.       ----------  FileManager . SynchWrite  ----------
  515.  
  516.       method SynchWrite (open: ptr to OpenFile, 
  517.                          sourceAddr, bytePos, numBytes: int) returns bool
  518.           --
  519.           -- This method reads "numBytes" from the memory address "sourceAddr"
  520.           -- and writes them to the file at "bytePos".  If everything
  521.           -- was written okay, it returns TRUE; if problems it returns FALSE.
  522.           --
  523.           -- It operates on an internal buffer by calling
  524.           -- "diskDriver.SynchReadSector" and "diskDriver.SynchWriteSector".
  525.           --
  526.           var sector, offset, posInBuffer, bytesToMove: int
  527.               fcb: ptr to FileControlBlock
  528.           -- print ("--------------------\n")
  529.           -- printHexVar ("SynchWrite called  sourceAddr", sourceAddr)
  530.           -- printIntVar ("                   bytePos", bytePos)
  531.           -- printIntVar ("                   numBytes", numBytes)
  532.           fileManagerLock.Lock()
  533.           if ! open || ! open.fcb || open.fcb.startingSectorOfFile < 0
  534.             FatalError ("FileManager.SynchWrite: file not properly opened")
  535.           endIf
  536.           fcb = open.fcb
  537.           while numBytes > 0
  538.             -- At this point sourceAddr and numBytes tell what work is left to do.
  539.             -- printHexVar ("NEXT MOVE:\n  sourceAddr", sourceAddr)
  540.             -- printIntVar ("  numBytes", numBytes)
  541.             -- printHexVar ("          ", numBytes)
  542.             -- printIntVar ("  startingSectorOfFile", fcb.startingSectorOfFile)
  543.             -- printIntVar ("  relativeSectorInBuffer", fcb.relativeSectorInBuffer)
  544.             -- printIntVar ("  bytePos", bytePos)
  545.             -- printHexVar ("         ", bytePos)
  546.             sector = bytePos / PAGE_SIZE
  547.             offset = bytePos % PAGE_SIZE
  548.             -- printIntVar ("  sector", sector)
  549.             -- printIntVar ("  offset", offset)
  550.             -- printHexVar ("        ", offset)
  551.             if fcb.relativeSectorInBuffer != sector
  552.               -- print ("  calling flush\n")
  553.               self.Flush (open)
  554.             endIf
  555.             posInBuffer = fcb.bufferPtr + offset
  556.             bytesToMove = Min (numBytes, PAGE_SIZE - offset)
  557.             if fcb.relativeSectorInBuffer == sector
  558.               -- No need to read the sector first
  559.             elseIf offset == 0 && bytesToMove == PAGE_SIZE
  560.               -- No need to read the sector first
  561.             else
  562.               -- printIntVar ("  READING SECTOR", sector + fcb.startingSectorOfFile)
  563.               diskDriver.SynchReadSector (sector + fcb.startingSectorOfFile,
  564.                                            1,
  565.                                            fcb.bufferPtr)
  566.             endIf
  567.             fcb.relativeSectorInBuffer = sector
  568.             fcb.bufferIsDirty = true
  569.             -- printHexVar ("  MOVING - sourceAddr", sourceAddr)
  570.             -- printHexVar ("         - target (posInBuffer)", posInBuffer)
  571.             -- printIntVar ("         - bytesToMove", bytesToMove)
  572.             MemoryCopy (posInBuffer, sourceAddr, bytesToMove)
  573.             sourceAddr = sourceAddr + bytesToMove
  574.             bytePos = bytePos + bytesToMove
  575.             numBytes = numBytes - bytesToMove
  576.             -- printHexVar ("  NEW sourceAddr", sourceAddr)
  577.             -- printIntVar ("  NEW bytePos", bytePos)
  578.             -- printHexVar ("             ", bytePos)
  579.             -- printIntVar ("  NEW numBytes", numBytes)
  580.             -- printHexVar ("              ", numBytes)
  581.           endWhile
  582.           fileManagerLock.Unlock()
  583.           -- print ("--------------------\n")
  584.           return true
  585.         endMethod
  586.  
  587.     endBehavior
  588.  
  589.   function copyUnalignedWord (destPtr, fromPtr: ptr to int)
  590.       var from, dest: ptr to char
  591.       from = fromPtr asPtrTo char
  592.       dest = destPtr asPtrTo char
  593.       *dest = *from
  594.       *(dest+1) = *(from+1)
  595.       *(dest+2) = *(from+2)
  596.       *(dest+3) = *(from+3)
  597.     endFunction
  598.  
  599.   function printFCB (fcb: ptr to FileControlBlock)
  600.       printInt (fcb.fcbID)
  601.       printChar (' ')
  602.     endFunction
  603.  
  604.   function printOpen (open: ptr to OpenFile)
  605.       print ("  0x")
  606.       printHex (open asInteger)
  607.       print (":  ")
  608.       open.Print ()
  609.     endFunction
  610.  
  611. -----------------------------  FileControlBlock  ---------------------------------
  612.  
  613.   behavior FileControlBlock
  614.  
  615.       ----------  FileControlBlock . Init  ----------
  616.       --
  617.       -- This method is called once at startup time.  It preallocates a buffer
  618.       -- in memory which may be needed when I/O is done on the file.
  619.       --
  620.       method Init ()
  621.           numberOfUsers = 0
  622.           bufferPtr = frameManager.GetAFrame ()
  623.           relativeSectorInBuffer = -1
  624.           bufferIsDirty = false
  625.           startingSectorOfFile = -1
  626.          endMethod
  627.  
  628.       ----------  FileControlBlock . Print  ----------
  629.  
  630.       method Print ()
  631.           print ("fcbID=")
  632.           printInt (fcbID)
  633.           print (",  numberOfUsers=")
  634.           printInt (numberOfUsers)
  635.           print (",  startingSector=")
  636.           printInt (startingSectorOfFile)
  637.           print (",  sizeOfFileInBytes=")
  638.           printInt (sizeOfFileInBytes)
  639.           print (",  bufferPtr=")
  640.           printHex (bufferPtr)
  641.           print (",  relativeSectorInBuffer=")
  642.           printInt (relativeSectorInBuffer)
  643.           nl ()
  644.         endMethod
  645.  
  646.     endBehavior
  647.  
  648. -----------------------------  OpenFile  ---------------------------------
  649.  
  650.   behavior OpenFile
  651.  
  652.       ----------  OpenFile . Print  ----------
  653.  
  654.       method Print ()
  655.           print ("    OPEN FILE:   currentPos=")
  656.           printInt (currentPos)
  657.           print (", fcb=")
  658.           if fcb
  659.             fcb.Print ()
  660.           else
  661.             print ("null\n")
  662.           endIf
  663.         endMethod
  664.  
  665.       ----------  OpenFile . ReadBytes  ----------
  666.  
  667.       method ReadBytes (targetAddr, numBytes: int) returns bool
  668.           --
  669.           -- This method reads "numBytes" from this file and stores
  670.           -- them at the address pointed to by "targetAddr".  If everything
  671.           -- was read okay, it returns TRUE; if problems it returns FALSE.
  672.           --
  673.           -- This method may block the caller.  This method is reentrant.
  674.           --
  675.           var pos: int
  676.           -- printIntVar ("OpenFile.ReadBytes    currentPos", currentPos)
  677.           fileManager.fileManagerLock.Lock ()
  678.           pos = currentPos
  679.           currentPos = currentPos + numBytes
  680.           fileManager.fileManagerLock.Unlock ()
  681.           return fileManager.SynchRead (self, targetAddr, pos, numBytes)
  682.         endMethod
  683.  
  684.       ----------  OpenFile . ReadInt  ----------
  685.  
  686.       method ReadInt () returns int
  687.           --
  688.           -- Read the next 4 bytes from a file and return it as an integer.
  689.           --
  690.           var i: int
  691.           if ! self.ReadBytes ((&i) asInteger, 4)
  692.             FatalError ("Within ReadInt: ReadBytes failed")
  693.           endIf
  694.           return i
  695.         endMethod
  696.  
  697.       ----------  OpenFile . LoadExecutable  ----------
  698.  
  699.       method LoadExecutable (addrSpace: ptr to AddrSpace) returns int
  700.         --
  701.         -- This method reads an executable "a.out" file from the disk, creates
  702.         -- a virtual address space (with all pages resident in memory), and
  703.         -- loads the executable program into the new address space.
  704.         --
  705.         -- The virtual address space will consist of (in this order):
  706.         --     The environment page(s)     see NUMBER_OF_ENVIRONMENT_PAGES
  707.         --     The text page(s)
  708.         --     The data page(s)
  709.         --     The bss page(s)
  710.         --     The stack page(s)           see USER_STACK_SIZE_IN_PAGES
  711.         --
  712.         -- The given "addrSpace" is assumed to be empty; this method will
  713.         -- allocate new frames and initialize the page table.
  714.         --
  715.         -- If all is okay, this method returns the initial PC, which will be
  716.         -- the address of the first word of the first text page.
  717.         --
  718.         -- If any problems arise, this method returns -1.
  719.         --
  720.           var nextVirtPage, addr: int
  721.               textSize, dataSize, bssSize, textStart, dataStart, bssStart: int
  722.               i, textSizeInPages, dataSizeInPages, bssSizeInPages: int
  723.  
  724.           -- Make sure this address space is empty...
  725.           if addrSpace.numberOfPages != 0
  726.             FatalError ("LoadExecutable: This virtual address space is not empty")
  727.           endIf
  728.          
  729.           -- Read and check the magic number...
  730.           if  self.ReadInt () != 0x424C5A78    -- in ASCII: "BLZx"
  731.             print ("LoadExecutable: Bad magic number\n")
  732.             return -1
  733.           endIf
  734.  
  735.           -- Read in the header info...
  736.           textSize = self.ReadInt ()
  737.           dataSize = self.ReadInt ()
  738.           bssSize = self.ReadInt ()
  739.           textStart = self.ReadInt ()
  740.           dataStart = self.ReadInt ()
  741.           bssStart = self.ReadInt ()
  742.  
  743.           -- Compute the size of the text segment in pages...
  744.           if textSize % PAGE_SIZE != 0
  745.             print ("LoadExecutable: The text segment size not a multiple of page size\n")
  746.             return -1
  747.           endIf
  748.           textSizeInPages = textSize / PAGE_SIZE
  749.  
  750.           -- Environment pages are filled in by the OS; make sure the executable
  751.           -- and the OS agree about how many there are to be...
  752.           if textStart != NUMBER_OF_ENVIRONMENT_PAGES * PAGE_SIZE
  753.             print ("LoadExecutable: The environment size does not match the 'loadAddr' info supplied to the linker\n")
  754.             return -1
  755.           endIf
  756.  
  757.           -- Compute the size of the data segment in pages...
  758.           if dataSize % PAGE_SIZE != 0
  759.             print ("LoadExecutable: The data segment size not a multiple of page size\n")
  760.             return -1
  761.           endIf
  762.           if dataStart != textStart + textSize
  763.             print ("LoadExecutable: dataStart != textStart + textSize\n")
  764.             return -1
  765.           endIf
  766.           dataSizeInPages = dataSize / PAGE_SIZE
  767.  
  768.           -- Compute the size of the bss segment in pages...
  769.           if bssSize % PAGE_SIZE != 0
  770.             print ("LoadExecutable: The bss segment size not a multiple of page size\n")
  771.             return -1
  772.           endIf
  773.           if bssStart != dataStart + dataSize
  774.             print ("LoadExecutable: bssStart != dataStart + dataSize\n")
  775.             return -1
  776.           endIf
  777.           bssSizeInPages = bssSize / PAGE_SIZE
  778.  
  779.           -- Compute how many pages to put into the address space...
  780.           i = textSizeInPages + dataSizeInPages + bssSizeInPages +
  781.               USER_STACK_SIZE_IN_PAGES + NUMBER_OF_ENVIRONMENT_PAGES
  782.  
  783.           /*****
  784.           printIntVar ("NUMBER_OF_ENVIRONMENT_PAGES", NUMBER_OF_ENVIRONMENT_PAGES)
  785.           printIntVar ("USER_STACK_SIZE_IN_PAGES", USER_STACK_SIZE_IN_PAGES)
  786.           printIntVar ("textSizeInPages", textSizeInPages)
  787.           printIntVar ("dataSizeInPages", dataSizeInPages)
  788.           printIntVar ("bssSizeInPages", bssSizeInPages)
  789.           printIntVar ("addrSpace.numberOfPages", addrSpace.numberOfPages)
  790.           printIntVar ("Number of pages in this address space", i)
  791.           printIntVar ("MAX_PAGES_PER_VIRT_SPACE", MAX_PAGES_PER_VIRT_SPACE)
  792.           *****/
  793.  
  794.           -- Allocate the frames...
  795.           if i > MAX_PAGES_PER_VIRT_SPACE
  796.             print ("LoadExecutable: This virtual address space exceeds the limit\n")
  797.             printIntVar ("LoadExecutable: Number of pages in this address space", i)
  798.             printIntVar ("LoadExecutable: MAX_PAGES_PER_VIRT_SPACE", MAX_PAGES_PER_VIRT_SPACE)
  799.             return -1
  800.           endIf
  801.           frameManager.GetNewFrames (addrSpace, i)
  802.  
  803.           -- print ("LoadExecutable: The address space just allocated...\n")
  804.           -- addrSpace.Print ()
  805.  
  806.           -- Read and check the separator...
  807.           if  self.ReadInt () != 0x2a2a2a2a
  808.             print ("LoadExecutable: Invalid file format - missing separator (1)\n")
  809.             frameManager.ReturnAllFrames (addrSpace)
  810.             return -1
  811.           endIf
  812.  
  813.           -- Read the text segment...
  814.           nextVirtPage = textStart / PAGE_SIZE
  815.           for i = 1 to textSizeInPages
  816.             addr = addrSpace.ExtractFrameAddr (nextVirtPage)
  817.             -- printIntVar ("About to read; nextVirtPage", nextVirtPage)
  818.             -- printHexVar ("               addr", addr)
  819.             if ! self.ReadBytes (addr, PAGE_SIZE)
  820.               print ("LoadExecutable: Problems reading from file (text)\n")
  821.               frameManager.ReturnAllFrames (addrSpace)
  822.               return -1
  823.             endIf
  824.             addrSpace.ClearWritable (nextVirtPage)
  825.             nextVirtPage = nextVirtPage + 1
  826.           endFor
  827.  
  828.           -- Read and check the separator...
  829.           if  self.ReadInt () != 0x2a2a2a2a
  830.             print ("LoadExecutable: Invalid file format - missing separator (2)\n")
  831.             frameManager.ReturnAllFrames (addrSpace)
  832.             return -1
  833.           endIf
  834.  
  835.           -- Read the data segment...
  836.           for i = 1 to dataSizeInPages
  837.             addr = addrSpace.ExtractFrameAddr (nextVirtPage)
  838.             -- printIntVar ("About to read; nextVirtPage", nextVirtPage)
  839.             -- printHexVar ("               addr", addr)
  840.             if ! self.ReadBytes (addr, PAGE_SIZE)
  841.               print ("LoadExecutable: Problems reading from file (text)\n")
  842.               frameManager.ReturnAllFrames (addrSpace)
  843.               return -1
  844.             endIf
  845.             nextVirtPage = nextVirtPage + 1
  846.           endFor
  847.  
  848.           -- Read and check the separator...
  849.           if  self.ReadInt () != 0x2a2a2a2a
  850.             print ("LoadExecutable: Invalid file format - missing separator (3)\n")
  851.             frameManager.ReturnAllFrames (addrSpace)
  852.             return -1
  853.           endIf
  854.  
  855.           -- Zero out the bss segment...
  856.           addr = addrSpace.ExtractFrameAddr (nextVirtPage)
  857.           -- printIntVar ("About to zero bss segment; page", nextVirtPage)
  858.           -- printHexVar ("                           addr", addr)
  859.           -- printHexVar ("                           bssSizeInBytes", bssSize)
  860.           MemoryZero (addr, bssSize)
  861.  
  862.           -- User programs begin execution at the first word of the text segment...
  863.           return textStart
  864.         endMethod
  865.  
  866.   endBehavior