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
/
version-1-0
/
OSProject
/
p5
/
FileStuff.c
< prev
next >
Wrap
Text File
|
2007-05-09
|
36KB
|
866 lines
----------------------------- DiskDriver ---------------------------------
const
DISK_STATUS_BUSY = 0x00000000
DISK_STATUS_OPERATION_COMPLETED_OK = 0x00000001
DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1 = 0x00000002
DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2 = 0x00000003
DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3 = 0x00000004
DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4 = 0x00000005
DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5 = 0x00000006
DISK_READ_COMMAND = 0x00000001
DISK_WRITE_COMMAND = 0x00000002
behavior DiskDriver
--
-- There is only one instance of this class. It provides "read" and "write"
-- methods to transfer data from and to the disk.
--
-- In this implementation, all I/O is synchronous. These methods perform
-- busy-waiting until the disk operation has completed.
---------- DiskDriver . Init ----------
method Init ()
print ("Initializing Disk Driver...\n")
DISK_STATUS_WORD_ADDRESS = 0x00FFFF08 asPtrTo int
DISK_COMMAND_WORD_ADDRESS = 0x00FFFF08 asPtrTo int
DISK_MEMORY_ADDRESS_REGISTER = 0x00FFFF0C asPtrTo int
DISK_SECTOR_NUMBER_REGISTER = 0x00FFFF10 asPtrTo int
DISK_SECTOR_COUNT_REGISTER = 0x00FFFF14 asPtrTo int
semToSignalOnCompletion = null
semUsedInSynchMethods = new Semaphore
semUsedInSynchMethods.Init (0)
diskBusy = new Mutex
diskBusy.Init ()
endMethod
---------- DiskDriver . SynchReadSector ----------
method SynchReadSector (sectorAddr, numberOfSectors, memoryAddr: int)
--
-- This method reads "numberOfSectors" sectors (of PAGE_SIZE bytes each)
-- from the disk and places the data in memory, starting at "memoryAddr".
-- It waits until the I/O is complete before returning.
--
-- If there is a (simulated) disk hardware failure, then this routine
-- simply tries again in an infinite loop, until it succeeds.
--
-- print ("SynchReadSector called\n")
-- printIntVar (" sectorAddr", sectorAddr)
-- printIntVar (" numberOfSectors", numberOfSectors)
-- printHexVar (" memoryAddr", memoryAddr)
diskBusy.Lock ()
while true
self.StartReadSector (sectorAddr, numberOfSectors, memoryAddr,
& semUsedInSynchMethods)
semUsedInSynchMethods.Wait ()
-- Check the return status
switch * DISK_STATUS_WORD_ADDRESS
case DISK_STATUS_OPERATION_COMPLETED_OK:
diskBusy.Unlock ()
return
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1:
FatalError ("Disk I/O error in SynchReadSector: Memory addr is not page-aligned or sector count is not positive")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2:
FatalError ("Disk I/O error in SynchReadSector: Attempt to access invalid memory address")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3:
FatalError ("Disk I/O error in SynchReadSector: Bad sectorAddr or sectorCount specifies non-existant sector")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4:
-- This case occurs when there is a hard or soft (simulated)
-- hardware error while performing the disk operation.
break
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5:
FatalError ("Disk I/O error in SynchReadSector: Bad command word")
default:
FatalError ("SynchReadSector: Unexpected status code")
endSwitch
-- print ("\n\nIn SynchReadSector: A simulated disk I/O error occurred...\n\n")
endWhile
endMethod
---------- DiskDriver . StartReadSector ----------
method StartReadSector (sectorAddr, numberOfSectors, memoryAddr: int,
whoCares: ptr to Semaphore)
--
-- This method reads "numberOfSectors" sectors (of PAGE_SIZE bytes each)
-- from the disk and places the data in memory, starting at "memoryAddr".
-- The "whoCares" argument is a Semaphore that we will signal after the
-- I/O operation is complete; if null no thread will be notified.
--
-- print ("StartReadSector called\n")
-- printIntVar (" sectorAddr", sectorAddr)
-- printIntVar (" numberOfSectors", numberOfSectors)
-- printHexVar (" memoryAddr", memoryAddr)
-- printHexVar (" whoCares", whoCares asInteger)
-- Save the semaphore
semToSignalOnCompletion = whoCares
-- Move the parameters to the disk and start the I/O
* DISK_MEMORY_ADDRESS_REGISTER = memoryAddr
* DISK_SECTOR_NUMBER_REGISTER = sectorAddr
* DISK_SECTOR_COUNT_REGISTER = numberOfSectors
* DISK_COMMAND_WORD_ADDRESS = DISK_READ_COMMAND -- Starts the I/O
endMethod
---------- DiskDriver . SynchWriteSector ----------
method SynchWriteSector (sectorAddr, numberOfSectors, memoryAddr: int)
--
-- This method writes "numberOfSectors" sectors (of PAGE_SIZE bytes each)
-- to the disk. It waits until the I/O is complete before returning.
--
-- If there is a (simulated) disk hardware failure, then this routine
-- simply tries again in an infinite loop, until it succeeds.
--
-- print ("SynchWriteSector called\n")
-- printIntVar (" sectorAddr", sectorAddr)
-- printIntVar (" numberOfSectors", numberOfSectors)
-- printHexVar (" memoryAddr", memoryAddr)
diskBusy.Lock ()
while true
self.StartWriteSector (sectorAddr, numberOfSectors, memoryAddr,
& semUsedInSynchMethods)
semUsedInSynchMethods.Wait ()
-- Check the return status
switch * DISK_STATUS_WORD_ADDRESS
case DISK_STATUS_OPERATION_COMPLETED_OK:
diskBusy.Unlock ()
return
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_1:
FatalError ("Disk I/O error in SynchWriteSector: Memory addr is not page-aligned or sector count is not positive")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_2:
FatalError ("Disk I/O error in SynchWriteSector: Attempt to access invalid memory address")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_3:
FatalError ("Disk I/O error in SynchWriteSector: Bad sectorAddr or sectorCount specifies non-existant sector")
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_4:
-- This case occurs when there is a hard or soft (simulated)
-- hardware error while performing the disk operation.
break
case DISK_STATUS_OPERATION_COMPLETED_WITH_ERROR_5:
FatalError ("Disk I/O error in SynchWriteSector: Bad command word")
default:
FatalError ("SynchWriteSector: Unexpected status code")
endSwitch
-- print ("\n\nIn SynchWriteSector: A simulated disk I/O error occurred...\n\n")
endWhile
endMethod
---------- DiskDriver . StartWriteSector ----------
method StartWriteSector (sectorAddr, numberOfSectors, memoryAddr: int,
whoCares: ptr to Semaphore)
--
-- This method writes "numberOfSectors" sectors (of PAGE_SIZE bytes each)
-- to the disk. It returns immediately after starting the I/O.
--
-- The "whoCares" argument is a Semaphore that we will signal after the
-- I/O operation is complete; if null no thread will be notified.
--
-- print ("SynchWriteSector called\n")
-- printIntVar (" sectorAddr", sectorAddr)
-- printIntVar (" numberOfSectors", numberOfSectors)
-- printHexVar (" memoryAddr", memoryAddr)
-- Save the semaphore
semToSignalOnCompletion = whoCares
* DISK_MEMORY_ADDRESS_REGISTER = memoryAddr
* DISK_SECTOR_NUMBER_REGISTER = sectorAddr
* DISK_SECTOR_COUNT_REGISTER = numberOfSectors
* DISK_COMMAND_WORD_ADDRESS = DISK_WRITE_COMMAND -- Starts the I/O
endMethod
endBehavior
----------------------------- FileManager ---------------------------------
behavior FileManager
---------- FileManager . Init ----------
method Init ()
--
-- This method is called once at kernel startup time to initialize
-- the one and only "FileManager" object. It is passed a pointer
-- to a frame of memory.
--
var i: int
print ("Initializing File Manager...\n")
fileManagerLock = new Mutex
fileManagerLock.Init ()
-- Initialize the FileControlBlock stuff
fcbFreeList = new List [FileControlBlock]
anFCBBecameFree = new Condition
anFCBBecameFree.Init ()
fcbTable = new array of FileControlBlock
{ MAX_NUMBER_OF_FILE_CONTROL_BLOCKS of new FileControlBlock }
for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
fcbTable[i].fcbID = i
fcbTable[i].Init()
fcbFreeList.AddToEnd (&fcbTable[i])
endFor
-- Initialize the OpenFile stuff
openFileFreeList = new List [OpenFile]
anOpenFileBecameFree = new Condition
anOpenFileBecameFree.Init ()
openFileTable = new array of OpenFile
{ MAX_NUMBER_OF_OPEN_FILES of new OpenFile }
for i = 0 to MAX_NUMBER_OF_OPEN_FILES-1
openFileTable[i].kind = FILE
openFileFreeList.AddToEnd (&openFileTable[i])
endFor
-- Create the special "stdin/stdout" open file
serialTerminalFile = new OpenFile
serialTerminalFile.kind = TERMINAL
-- Read in sector 0 from the disk. This is the
-- "Stub System" directory page. We'll just keep this around
-- forever, for use whenever we want to open a file.
directoryFrame = frameManager.GetAFrame ()
diskDriver.SynchReadSector (0, -- sector to read
1, -- number of sectors to read
directoryFrame)
endMethod
---------- FileManager . Print ----------
method Print ()
var i: int
fileManagerLock.Lock () -- Need lock since we touch freeLists
print ("Here is the FileControlBlock table...\n")
for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
print (" ")
printInt (i)
print (": ")
fcbTable[i].Print()
endFor
print ("Here is the FREE list of FileControlBlocks:\n ")
fcbFreeList.ApplyToEach (printFCB)
nl ()
print ("Here is the OpenFile table...\n")
for i = 0 to MAX_NUMBER_OF_OPEN_FILES-1
print (" ")
printInt (i)
print (": 0x")
printHex ((& openFileTable[i]) asInteger)
print (": ")
openFileTable[i].Print()
endFor
print ("Here is the FREE list of OpenFiles:\n")
openFileFreeList.ApplyToEach (printOpen)
fileManagerLock.Unlock ()
endMethod
---------- FileManager . Open ----------
method Open (filename: String) returns ptr to OpenFile
--
-- This method is called to open a file. It returns pointer to
-- a newly allocated OpenFile. It will set its "numberOfUsers"
-- count to 1.
--
-- The file must already exist on the disk. If it cannot be found,
-- this method returns null.
--
-- This method is reentrant, and may block the caller.
--
var open: ptr to OpenFile
fcb: ptr to FileControlBlock
-- First, get an FCB that points to the file.
-- This will increment fcb.numberOfUsers.
fcb = fileManager.FindFCB (filename)
if fcb == null
return null
endIf
-- Next, allocate an OpenFile, waiting if necessary.
fileManagerLock.Lock()
while openFileFreeList.IsEmpty ()
anOpenFileBecameFree.Wait (& fileManagerLock)
endWhile
open = openFileFreeList.Remove ()
-- Connect it to this FCB and set its "numberOfUsers" count.
open.fcb = fcb
open.numberOfUsers = 1
-- printHexVar ("open.fcb", open.fcb asInteger)
open.currentPos = 0
-- Release FileManagerLock and return a pointer to the OpenFile object
fileManagerLock.Unlock()
return open
endMethod
---------- FileManager . FindFCB ----------
method FindFCB (filename: String) returns ptr to FileControlBlock
--
-- This method is called when opening a file. The file may already be
-- open; if so we return a pointer to the FCB that describes that
-- file. If not, we allocate a new FCB and return a pointer to it.
--
-- The file must already exist on the disk. If it cannot be found,
-- this method returns null.
--
-- The numberOfUsers field in the FCB is incremented.
--
-- This implementation is a "dummy" implementation, using the "stub"
-- file system. The stub file system has a single directory which
-- is stored in sector 0. When the fileManager was initialized, sector
-- 0 was pre-read, so all we do here is consult it to locate the
-- the file. Then we store the relevant info in the FCB.
--
-- This method is reentrant, and may block the caller.
--
var i, start, numFiles, fileLen, fileNameLen: int
fcb: ptr to FileControlBlock
p: ptr to int
-- print ("Opening a file\n")
-- Begin the search with byte 0 of the directory sector
p = directoryFrame asPtrTo int
-- Check the magic number
i = *p
p = p + 4
if i != 0x73747562 -- in ASCII this is "stub"
FatalError ("Magic number in sector 0 of stub file system is bad")
endIf
-- Get the number of files in the directory
numFiles = *p
p = p + 4
i = *p -- This is the nextFreeSector; ignore it.
p = p + 4
-- Run through each directory entry, looking for a match
while numFiles > 0
copyUnalignedWord (&start, p)
p = p + 4
copyUnalignedWord (&fileLen, p)
p = p + 4
copyUnalignedWord (&fileNameLen, p)
p = p + 4
if fileNameLen == filename arraySize &&
MemoryEqual (p asPtrTo char, &filename[0], fileNameLen)
break
endIf
p = p + fileNameLen
numFiles = numFiles - 1
endWhile
-- If we didn't find a matching name, return null
if numFiles <= 0
return null
endIf
fileManagerLock.Lock()
-- See if there is an FCB for this file; if so return it.
for i = 0 to MAX_NUMBER_OF_FILE_CONTROL_BLOCKS-1
fcb = &fcbTable[i]
if fcb.startingSectorOfFile == start
fcb.numberOfUsers = fcb.numberOfUsers + 1
fileManagerLock.Unlock()
return fcb
endIf
endFor
-- Get an unused FCB, waiting until one becomes available
while fcbFreeList.IsEmpty ()
anFCBBecameFree.Wait (& fileManagerLock)
endWhile
fcb = fcbFreeList.Remove ()
-- Safe to unlock now, since no one else will use this FCB
fileManagerLock.Unlock()
-- Set the FCB up, and return it.
fcb.startingSectorOfFile = start
fcb.sizeOfFileInBytes = fileLen
fcb.numberOfUsers = 1
if fcb.relativeSectorInBuffer >= 0 || fcb.bufferIsDirty
FatalError ("In FileManager.Open: a free FCB appears not to have been closed properly")
endIf
return fcb
endMethod
---------- FileManager . Close ----------
--
-- This method is called to close an OpenFile. If there is a pending
-- write (i.e., the buffer is dirty) then it is written out first.
--
-- The "numberOfUsers" for the OpenFile is decremented and, if zero,
-- the OpenFile is freed. If the OpenFile is freed, then the
-- "numberOfUsers" for the FCB is decremented. If it too is zero, the
-- FCB is freed.
--
method Close (open: ptr to OpenFile)
var fcb: ptr to FileControlBlock
if open == & serialTerminalFile
return
endIf
fileManagerLock.Lock()
fileManager.Flush (open)
fcb = open.fcb
open.numberOfUsers = open.numberOfUsers - 1
if open.numberOfUsers <= 0
openFileFreeList.AddToEnd (open)
anOpenFileBecameFree.Signal (& fileManagerLock)
fcb.numberOfUsers = fcb.numberOfUsers - 1
if fcb.numberOfUsers <= 0
fcbFreeList.AddToEnd (fcb)
anFCBBecameFree.Signal (& fileManagerLock)
endIf
endIf
fileManagerLock.Unlock()
endMethod
---------- FileManager . Flush ----------
method Flush (open: ptr to OpenFile)
--
-- This method writes out the buffer, if it is dirty. This method
-- assumes the caller already holds the fileManagerLock.
--
if open.fcb.bufferIsDirty
if open.fcb.relativeSectorInBuffer < 0
FatalError ("FileManager.Flush: buffer is dirty but relativeSectorInBuffer = -1")
endIf
open.fcb.bufferIsDirty = false
diskDriver.SynchWriteSector (
open.fcb.relativeSectorInBuffer+open.fcb.startingSectorOfFile,
1,
open.fcb.bufferPtr)
endIf
endMethod
---------- FileManager . SynchRead ----------
method SynchRead (open: ptr to OpenFile,
targetAddr, bytePos, numBytes: int) returns bool
--
-- This method reads "numBytes" from this file and stores
-- them at the address pointed to by "targetAddr". If everything
-- was read okay, it returns TRUE; if problems it returns FALSE.
--
-- It reads a page at a time into an internal buffer
-- by calling "diskDriver.SynchReadSector".
--
var sector, offset, posInBuffer, bytesToMove: int
fcb: ptr to FileControlBlock
-- printHexVar ("SynchRead called targetAddr", targetAddr)
-- printIntVar (" bytePos", bytePos)
-- printIntVar (" numBytes", numBytes)
fileManagerLock.Lock()
if ! open || ! open.fcb || open.fcb.startingSectorOfFile < 0
FatalError ("FileManager.SynchRead: file not properly opened")
endIf
fcb = open.fcb
while numBytes > 0
-- At this point targetAddr and numBytes tell what work is left to do.
-- printHexVar ("NEXT MOVE:\n targetAddr", targetAddr)
-- printIntVar (" numBytes", numBytes)
-- printHexVar (" ", numBytes)
-- printIntVar (" startingSectorOfFile", fcb.startingSectorOfFile)
-- printIntVar (" relativeSectorInBuffer", fcb.relativeSectorInBuffer)
-- printIntVar (" bytePos", bytePos)
-- printHexVar (" ", bytePos)
sector = bytePos / PAGE_SIZE
offset = bytePos % PAGE_SIZE
-- printIntVar (" sector", sector)
-- printIntVar (" offset", offset)
-- printHexVar (" ", offset)
if fcb.relativeSectorInBuffer != sector
self.Flush (open)
-- printIntVar (" READING SECTOR", sector+startingSectorOfFile)
diskDriver.SynchReadSector (sector + fcb.startingSectorOfFile,
1,
fcb.bufferPtr)
fcb.relativeSectorInBuffer = sector
fcb.bufferIsDirty = false -- (This is unnecessary since Flush does it)
endIf
posInBuffer = fcb.bufferPtr + offset
bytesToMove = Min (numBytes, PAGE_SIZE - offset)
-- printHexVar (" MOVING - targetAddr", targetAddr)
-- printHexVar (" - source addr (posInBuffer)", posInBuffer)
-- printIntVar (" - bytesToMove", bytesToMove)
MemoryCopy (targetAddr, posInBuffer, bytesToMove)
targetAddr = targetAddr + bytesToMove
bytePos = bytePos + bytesToMove
numBytes = numBytes - bytesToMove
-- printHexVar (" NEW targetAddr", targetAddr)
-- printIntVar (" NEW bytePos", bytePos)
-- printHexVar (" ", bytePos)
-- printIntVar (" NEW numBytes", numBytes)
-- printHexVar (" ", numBytes)
endWhile
fileManagerLock.Unlock()
return true
endMethod
---------- FileManager . SynchWrite ----------
method SynchWrite (open: ptr to OpenFile,
sourceAddr, bytePos, numBytes: int) returns bool
--
-- This method reads "numBytes" from the memory address "sourceAddr"
-- and writes them to the file at "bytePos". If everything
-- was written okay, it returns TRUE; if problems it returns FALSE.
--
-- It operates on an internal buffer by calling
-- "diskDriver.SynchReadSector" and "diskDriver.SynchWriteSector".
--
var sector, offset, posInBuffer, bytesToMove: int
fcb: ptr to FileControlBlock
-- print ("--------------------\n")
-- printHexVar ("SynchWrite called sourceAddr", sourceAddr)
-- printIntVar (" bytePos", bytePos)
-- printIntVar (" numBytes", numBytes)
fileManagerLock.Lock()
if ! open || ! open.fcb || open.fcb.startingSectorOfFile < 0
FatalError ("FileManager.SynchWrite: file not properly opened")
endIf
fcb = open.fcb
while numBytes > 0
-- At this point sourceAddr and numBytes tell what work is left to do.
-- printHexVar ("NEXT MOVE:\n sourceAddr", sourceAddr)
-- printIntVar (" numBytes", numBytes)
-- printHexVar (" ", numBytes)
-- printIntVar (" startingSectorOfFile", fcb.startingSectorOfFile)
-- printIntVar (" relativeSectorInBuffer", fcb.relativeSectorInBuffer)
-- printIntVar (" bytePos", bytePos)
-- printHexVar (" ", bytePos)
sector = bytePos / PAGE_SIZE
offset = bytePos % PAGE_SIZE
-- printIntVar (" sector", sector)
-- printIntVar (" offset", offset)
-- printHexVar (" ", offset)
if fcb.relativeSectorInBuffer != sector
-- print (" calling flush\n")
self.Flush (open)
endIf
posInBuffer = fcb.bufferPtr + offset
bytesToMove = Min (numBytes, PAGE_SIZE - offset)
if fcb.relativeSectorInBuffer == sector
-- No need to read the sector first
elseIf offset == 0 && bytesToMove == PAGE_SIZE
-- No need to read the sector first
else
-- printIntVar (" READING SECTOR", sector + fcb.startingSectorOfFile)
diskDriver.SynchReadSector (sector + fcb.startingSectorOfFile,
1,
fcb.bufferPtr)
endIf
fcb.relativeSectorInBuffer = sector
fcb.bufferIsDirty = true
-- printHexVar (" MOVING - sourceAddr", sourceAddr)
-- printHexVar (" - target (posInBuffer)", posInBuffer)
-- printIntVar (" - bytesToMove", bytesToMove)
MemoryCopy (posInBuffer, sourceAddr, bytesToMove)
sourceAddr = sourceAddr + bytesToMove
bytePos = bytePos + bytesToMove
numBytes = numBytes - bytesToMove
-- printHexVar (" NEW sourceAddr", sourceAddr)
-- printIntVar (" NEW bytePos", bytePos)
-- printHexVar (" ", bytePos)
-- printIntVar (" NEW numBytes", numBytes)
-- printHexVar (" ", numBytes)
endWhile
fileManagerLock.Unlock()
-- print ("--------------------\n")
return true
endMethod
endBehavior
function copyUnalignedWord (destPtr, fromPtr: ptr to int)
var from, dest: ptr to char
from = fromPtr asPtrTo char
dest = destPtr asPtrTo char
*dest = *from
*(dest+1) = *(from+1)
*(dest+2) = *(from+2)
*(dest+3) = *(from+3)
endFunction
function printFCB (fcb: ptr to FileControlBlock)
printInt (fcb.fcbID)
printChar (' ')
endFunction
function printOpen (open: ptr to OpenFile)
print (" 0x")
printHex (open asInteger)
print (": ")
open.Print ()
endFunction
----------------------------- FileControlBlock ---------------------------------
behavior FileControlBlock
---------- FileControlBlock . Init ----------
--
-- This method is called once at startup time. It preallocates a buffer
-- in memory which may be needed when I/O is done on the file.
--
method Init ()
numberOfUsers = 0
bufferPtr = frameManager.GetAFrame ()
relativeSectorInBuffer = -1
bufferIsDirty = false
startingSectorOfFile = -1
endMethod
---------- FileControlBlock . Print ----------
method Print ()
print ("fcbID=")
printInt (fcbID)
print (", numberOfUsers=")
printInt (numberOfUsers)
print (", startingSector=")
printInt (startingSectorOfFile)
print (", sizeOfFileInBytes=")
printInt (sizeOfFileInBytes)
print (", bufferPtr=")
printHex (bufferPtr)
print (", relativeSectorInBuffer=")
printInt (relativeSectorInBuffer)
nl ()
endMethod
endBehavior
----------------------------- OpenFile ---------------------------------
behavior OpenFile
---------- OpenFile . Print ----------
method Print ()
print (" OPEN FILE: currentPos=")
printInt (currentPos)
print (", fcb=")
if fcb
fcb.Print ()
else
print ("null\n")
endIf
endMethod
---------- OpenFile . ReadBytes ----------
method ReadBytes (targetAddr, numBytes: int) returns bool
--
-- This method reads "numBytes" from this file and stores
-- them at the address pointed to by "targetAddr". If everything
-- was read okay, it returns TRUE; if problems it returns FALSE.
--
-- This method may block the caller. This method is reentrant.
--
var pos: int
-- printIntVar ("OpenFile.ReadBytes currentPos", currentPos)
fileManager.fileManagerLock.Lock ()
pos = currentPos
currentPos = currentPos + numBytes
fileManager.fileManagerLock.Unlock ()
return fileManager.SynchRead (self, targetAddr, pos, numBytes)
endMethod
---------- OpenFile . ReadInt ----------
method ReadInt () returns int
--
-- Read the next 4 bytes from a file and return it as an integer.
--
var i: int
if ! self.ReadBytes ((&i) asInteger, 4)
FatalError ("Within ReadInt: ReadBytes failed")
endIf
return i
endMethod
---------- OpenFile . LoadExecutable ----------
method LoadExecutable (addrSpace: ptr to AddrSpace) returns int
--
-- This method reads an executable "a.out" file from the disk, creates
-- a virtual address space (with all pages resident in memory), and
-- loads the executable program into the new address space.
--
-- The virtual address space will consist of (in this order):
-- The environment page(s) see NUMBER_OF_ENVIRONMENT_PAGES
-- The text page(s)
-- The data page(s)
-- The bss page(s)
-- The stack page(s) see USER_STACK_SIZE_IN_PAGES
--
-- The given "addrSpace" is assumed to be empty; this method will
-- allocate new frames and initialize the page table.
--
-- If all is okay, this method returns the initial PC, which will be
-- the address of the first word of the first text page.
--
-- If any problems arise, this method returns -1.
--
var nextVirtPage, addr: int
textSize, dataSize, bssSize, textStart, dataStart, bssStart: int
i, textSizeInPages, dataSizeInPages, bssSizeInPages: int
-- Make sure this address space is empty...
if addrSpace.numberOfPages != 0
FatalError ("LoadExecutable: This virtual address space is not empty")
endIf
-- Read and check the magic number...
if self.ReadInt () != 0x424C5A78 -- in ASCII: "BLZx"
print ("LoadExecutable: Bad magic number\n")
return -1
endIf
-- Read in the header info...
textSize = self.ReadInt ()
dataSize = self.ReadInt ()
bssSize = self.ReadInt ()
textStart = self.ReadInt ()
dataStart = self.ReadInt ()
bssStart = self.ReadInt ()
-- Compute the size of the text segment in pages...
if textSize % PAGE_SIZE != 0
print ("LoadExecutable: The text segment size not a multiple of page size\n")
return -1
endIf
textSizeInPages = textSize / PAGE_SIZE
-- Environment pages are filled in by the OS; make sure the executable
-- and the OS agree about how many there are to be...
if textStart != NUMBER_OF_ENVIRONMENT_PAGES * PAGE_SIZE
print ("LoadExecutable: The environment size does not match the 'loadAddr' info supplied to the linker\n")
return -1
endIf
-- Compute the size of the data segment in pages...
if dataSize % PAGE_SIZE != 0
print ("LoadExecutable: The data segment size not a multiple of page size\n")
return -1
endIf
if dataStart != textStart + textSize
print ("LoadExecutable: dataStart != textStart + textSize\n")
return -1
endIf
dataSizeInPages = dataSize / PAGE_SIZE
-- Compute the size of the bss segment in pages...
if bssSize % PAGE_SIZE != 0
print ("LoadExecutable: The bss segment size not a multiple of page size\n")
return -1
endIf
if bssStart != dataStart + dataSize
print ("LoadExecutable: bssStart != dataStart + dataSize\n")
return -1
endIf
bssSizeInPages = bssSize / PAGE_SIZE
-- Compute how many pages to put into the address space...
i = textSizeInPages + dataSizeInPages + bssSizeInPages +
USER_STACK_SIZE_IN_PAGES + NUMBER_OF_ENVIRONMENT_PAGES
/*****
printIntVar ("NUMBER_OF_ENVIRONMENT_PAGES", NUMBER_OF_ENVIRONMENT_PAGES)
printIntVar ("USER_STACK_SIZE_IN_PAGES", USER_STACK_SIZE_IN_PAGES)
printIntVar ("textSizeInPages", textSizeInPages)
printIntVar ("dataSizeInPages", dataSizeInPages)
printIntVar ("bssSizeInPages", bssSizeInPages)
printIntVar ("addrSpace.numberOfPages", addrSpace.numberOfPages)
printIntVar ("Number of pages in this address space", i)
printIntVar ("MAX_PAGES_PER_VIRT_SPACE", MAX_PAGES_PER_VIRT_SPACE)
*****/
-- Allocate the frames...
if i > MAX_PAGES_PER_VIRT_SPACE
print ("LoadExecutable: This virtual address space exceeds the limit\n")
printIntVar ("LoadExecutable: Number of pages in this address space", i)
printIntVar ("LoadExecutable: MAX_PAGES_PER_VIRT_SPACE", MAX_PAGES_PER_VIRT_SPACE)
return -1
endIf
frameManager.GetNewFrames (addrSpace, i)
-- print ("LoadExecutable: The address space just allocated...\n")
-- addrSpace.Print ()
-- Read and check the separator...
if self.ReadInt () != 0x2a2a2a2a
print ("LoadExecutable: Invalid file format - missing separator (1)\n")
frameManager.ReturnAllFrames (addrSpace)
return -1
endIf
-- Read the text segment...
nextVirtPage = textStart / PAGE_SIZE
for i = 1 to textSizeInPages
addr = addrSpace.ExtractFrameAddr (nextVirtPage)
-- printIntVar ("About to read; nextVirtPage", nextVirtPage)
-- printHexVar (" addr", addr)
if ! self.ReadBytes (addr, PAGE_SIZE)
print ("LoadExecutable: Problems reading from file (text)\n")
frameManager.ReturnAllFrames (addrSpace)
return -1
endIf
addrSpace.ClearWritable (nextVirtPage)
nextVirtPage = nextVirtPage + 1
endFor
-- Read and check the separator...
if self.ReadInt () != 0x2a2a2a2a
print ("LoadExecutable: Invalid file format - missing separator (2)\n")
frameManager.ReturnAllFrames (addrSpace)
return -1
endIf
-- Read the data segment...
for i = 1 to dataSizeInPages
addr = addrSpace.ExtractFrameAddr (nextVirtPage)
-- printIntVar ("About to read; nextVirtPage", nextVirtPage)
-- printHexVar (" addr", addr)
if ! self.ReadBytes (addr, PAGE_SIZE)
print ("LoadExecutable: Problems reading from file (text)\n")
frameManager.ReturnAllFrames (addrSpace)
return -1
endIf
nextVirtPage = nextVirtPage + 1
endFor
-- Read and check the separator...
if self.ReadInt () != 0x2a2a2a2a
print ("LoadExecutable: Invalid file format - missing separator (3)\n")
frameManager.ReturnAllFrames (addrSpace)
return -1
endIf
-- Zero out the bss segment...
addr = addrSpace.ExtractFrameAddr (nextVirtPage)
-- printIntVar ("About to zero bss segment; page", nextVirtPage)
-- printHexVar (" addr", addr)
-- printHexVar (" bssSizeInBytes", bssSize)
MemoryZero (addr, bssSize)
-- User programs begin execution at the first word of the text segment...
return textStart
endMethod
endBehavior