Page principale | Liste des namespaces | Hiérarchie des classes | Liste des classes | Répertoires | Liste des fichiers | Membres de namespace | Membres de classe | Membres de fichier

addrspace.cc

Aller à la documentation de ce fichier.
00001 // addrspace.cc 
00002 //      Routines to manage address spaces (executing user programs).
00003 //
00004 //      In order to run a user program, you must:
00005 //
00006 //      1. link with the -n -T 0 option 
00007 //      2. run coff2noff to convert the object file to Nachos format
00008 //              (Nachos object code format is essentially just a simpler
00009 //              version of the UNIX executable object code format)
00010 //      3. load the NOFF file into the Nachos file system
00011 //              (if you are using the "stub" file system, you
00012 //              don't need to do this last step)
00013 //
00014 // Copyright (c) 1992-1996 The Regents of the University of California.
00015 // All rights reserved.  See copyright.h for copyright notice and limitation 
00016 // of liability and disclaimer of warranty provisions.
00017 
00018 #include "copyright.h"
00019 #include "main.h"
00020 #include "addrspace.h"
00021 #include "machine.h"
00022 #include "noff.h"
00023 
00024 //----------------------------------------------------------------------
00025 // SwapHeader
00026 //      Do little endian to big endian conversion on the bytes in the 
00027 //      object file header, in case the file was generated on a little
00028 //      endian machine, and we're now running on a big endian machine.
00029 //----------------------------------------------------------------------
00030 
00031 static void 
00032 SwapHeader (NoffHeader *noffH)
00033 {
00034     noffH->noffMagic = WordToHost(noffH->noffMagic);
00035     noffH->code.size = WordToHost(noffH->code.size);
00036     noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
00037     noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
00038 #ifdef RDATA
00039     noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
00040     noffH->readonlyData.virtualAddr = 
00041            WordToHost(noffH->readonlyData.virtualAddr);
00042     noffH->readonlyData.inFileAddr = 
00043            WordToHost(noffH->readonlyData.inFileAddr);
00044 #endif 
00045     noffH->initData.size = WordToHost(noffH->initData.size);
00046     noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
00047     noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
00048     noffH->uninitData.size = WordToHost(noffH->uninitData.size);
00049     noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
00050     noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
00051 
00052 #ifdef RDATA
00053     DEBUG(dbgAddr, "code = " << noffH->code.size <<  
00054                    " readonly = " << noffH->readonlyData.size <<
00055                    " init = " << noffH->initData.size <<
00056                    " uninit = " << noffH->uninitData.size << "\n");
00057 #endif
00058 }
00059 
00060 //----------------------------------------------------------------------
00061 // AddrSpace::AddrSpace
00062 //      Create an address space to run a user program.
00063 //      Set up the translation from program memory to physical 
00064 //      memory.  For now, this is really simple (1:1), since we are
00065 //      only uniprogramming, and we have a single unsegmented page table
00066 //----------------------------------------------------------------------
00067 
00068 AddrSpace::AddrSpace()
00069 {
00070     pageTable = new TranslationEntry[NumPhysPages];
00071     for (int i = 0; i < NumPhysPages; i++) {
00072         pageTable[i].virtualPage = i;   // for now, virt page # = phys page #
00073         pageTable[i].physicalPage = i;
00074         pageTable[i].valid = TRUE;
00075         pageTable[i].use = FALSE;
00076         pageTable[i].dirty = FALSE;
00077         pageTable[i].readOnly = FALSE;  
00078     }
00079     
00080     // zero out the entire address space
00081     bzero(kernel->machine->mainMemory, MemorySize);
00082 }
00083 
00084 //----------------------------------------------------------------------
00085 // AddrSpace::~AddrSpace
00086 //      Dealloate an address space.
00087 //----------------------------------------------------------------------
00088 
00089 AddrSpace::~AddrSpace()
00090 {
00091    delete pageTable;
00092 }
00093 
00094 
00095 //----------------------------------------------------------------------
00096 // AddrSpace::Load
00097 //      Load a user program into memory from a file.
00098 //
00099 //      Assumes that the page table has been initialized, and that
00100 //      the object code file is in NOFF format.
00101 //
00102 //      "fileName" is the file containing the object code to load into memory
00103 //----------------------------------------------------------------------
00104 
00105 bool 
00106 AddrSpace::Load(char *fileName) 
00107 {
00108     OpenFile *executable = kernel->fileSystem->Open(fileName);
00109     NoffHeader noffH;
00110     unsigned int size;
00111 
00112     if (executable == NULL) {
00113         cerr << "Unable to open file " << fileName << "\n";
00114         return FALSE;
00115     }
00116 
00117     executable->ReadAt((char *)&noffH, sizeof(noffH), 0);
00118     if ((noffH.noffMagic != NOFFMAGIC) && 
00119                 (WordToHost(noffH.noffMagic) == NOFFMAGIC))
00120         SwapHeader(&noffH);
00121     ASSERT(noffH.noffMagic == NOFFMAGIC);
00122 
00123 #ifdef RDATA
00124 // how big is address space?
00125     size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
00126            noffH.uninitData.size + UserStackSize;       
00127                                                 // we need to increase the size
00128                                                 // to leave room for the stack
00129 #else
00130 // how big is address space?
00131     size = noffH.code.size + noffH.initData.size + noffH.uninitData.size 
00132                         + UserStackSize;        // we need to increase the size
00133                                                 // to leave room for the stack
00134 #endif
00135     numPages = divRoundUp(size, PageSize);
00136     size = numPages * PageSize;
00137 
00138     ASSERT(numPages <= NumPhysPages);           // check we're not trying
00139                                                 // to run anything too big --
00140                                                 // at least until we have
00141                                                 // virtual memory
00142 
00143     DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
00144 
00145 // then, copy in the code and data segments into memory
00146 // Note: this code assumes that virtual address = physical address
00147     if (noffH.code.size > 0) {
00148         DEBUG(dbgAddr, "Initializing code segment.");
00149         DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
00150         executable->ReadAt(
00151                 &(kernel->machine->mainMemory[noffH.code.virtualAddr]), 
00152                         noffH.code.size, noffH.code.inFileAddr);
00153     }
00154     if (noffH.initData.size > 0) {
00155         DEBUG(dbgAddr, "Initializing data segment.");
00156         DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
00157         executable->ReadAt(
00158                 &(kernel->machine->mainMemory[noffH.initData.virtualAddr]),
00159                         noffH.initData.size, noffH.initData.inFileAddr);
00160     }
00161 
00162 #ifdef RDATA
00163     if (noffH.readonlyData.size > 0) {
00164         DEBUG(dbgAddr, "Initializing read only data segment.");
00165         DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
00166         executable->ReadAt(
00167                 &(kernel->machine->mainMemory[noffH.readonlyData.virtualAddr]),
00168                         noffH.readonlyData.size, noffH.readonlyData.inFileAddr);
00169     }
00170 #endif
00171 
00172     delete executable;                  // close file
00173     return TRUE;                        // success
00174 }
00175 
00176 //----------------------------------------------------------------------
00177 // AddrSpace::Execute
00178 //      Run a user program using the current thread
00179 //
00180 //      The program is assumed to have already been loaded into
00181 //      the address space
00182 //
00183 //----------------------------------------------------------------------
00184 
00185 void 
00186 AddrSpace::Execute() 
00187 {
00188 
00189    // kernel->currentThread->space = this;
00190 
00191     this->InitRegisters();              // set the initial register values
00192     this->RestoreState();               // load page table register
00193 
00194     kernel->machine->Run();             // jump to the user progam
00195 
00196     ASSERTNOTREACHED();                 // machine->Run never returns;
00197                                         // the address space exits
00198                                         // by doing the syscall "exit"
00199 }
00200 
00201 
00202 //----------------------------------------------------------------------
00203 // AddrSpace::InitRegisters
00204 //      Set the initial values for the user-level register set.
00205 //
00206 //      We write these directly into the "machine" registers, so
00207 //      that we can immediately jump to user code.  Note that these
00208 //      will be saved/restored into the currentThread->userRegisters
00209 //      when this thread is context switched out.
00210 //----------------------------------------------------------------------
00211 
00212 void
00213 AddrSpace::InitRegisters()
00214 {
00215     Machine *machine = kernel->machine;
00216     int i;
00217 
00218     for (i = 0; i < NumTotalRegs; i++)
00219         machine->WriteRegister(i, 0);
00220 
00221     // Initial program counter -- must be location of "Start", which
00222     //  is assumed to be virtual address zero
00223     machine->WriteRegister(PCReg, 0);   
00224 
00225     // Need to also tell MIPS where next instruction is, because
00226     // of branch delay possibility
00227     // Since instructions occupy four bytes each, the next instruction
00228     // after start will be at virtual address four.
00229     machine->WriteRegister(NextPCReg, 4);
00230 
00231    // Set the stack register to the end of the address space, where we
00232    // allocated the stack; but subtract off a bit, to make sure we don't
00233    // accidentally reference off the end!
00234     machine->WriteRegister(StackReg, numPages * PageSize - 16);
00235     DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
00236 }
00237 
00238 //----------------------------------------------------------------------
00239 // AddrSpace::SaveState
00240 //      On a context switch, save any machine state, specific
00241 //      to this address space, that needs saving.
00242 //
00243 //      For now, don't need to save anything!
00244 //----------------------------------------------------------------------
00245 
00246 void AddrSpace::SaveState() 
00247 {}
00248 
00249 //----------------------------------------------------------------------
00250 // AddrSpace::RestoreState
00251 //      On a context switch, restore the machine state so that
00252 //      this address space can run.
00253 //
00254 //      For now, tell the machine where to find the page table.
00255 //----------------------------------------------------------------------
00256 
00257 void AddrSpace::RestoreState() 
00258 {
00259     kernel->machine->pageTable = pageTable;
00260     kernel->machine->pageTableSize = numPages;
00261 }
00262 
00263 
00264 //----------------------------------------------------------------------
00265 // AddrSpace::Translate
00266 //  Translate the virtual address in _vaddr_ to a physical address
00267 //  and store the physical address in _paddr_.
00268 //  The flag _isReadWrite_ is false (0) for read-only access; true (1)
00269 //  for read-write access.
00270 //  Return any exceptions caused by the address translation.
00271 //----------------------------------------------------------------------
00272 ExceptionType
00273 AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite)
00274 {
00275     TranslationEntry *pte;
00276     int               pfn;
00277     unsigned int      vpn    = vaddr / PageSize;
00278     unsigned int      offset = vaddr % PageSize;
00279 
00280     if(vpn >= numPages) {
00281         return AddressErrorException;
00282     }
00283 
00284     pte = &pageTable[vpn];
00285 
00286     if(isReadWrite && pte->readOnly) {
00287         return ReadOnlyException;
00288     }
00289 
00290     pfn = pte->physicalPage;
00291 
00292     // if the pageFrame is too big, there is something really wrong!
00293     // An invalid translation was loaded into the page table or TLB.
00294     if (pfn >= NumPhysPages) {
00295         DEBUG(dbgAddr, "Illegal physical page " << pfn);
00296         return BusErrorException;
00297     }
00298 
00299     pte->use = TRUE;          // set the use, dirty bits
00300 
00301     if(isReadWrite)
00302         pte->dirty = TRUE;
00303 
00304     *paddr = pfn*PageSize + offset;
00305 
00306     ASSERT((*paddr < MemorySize));
00307 
00308     //cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
00309     //  ", paddr: " << *paddr << "\n";
00310 
00311     return NoException;
00312 }
00313 
00314 
00315 
00316 

Généré le Sun Jan 15 00:45:45 2006 pour Système NachOS : par  doxygen 1.4.4