home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume44 / toy_os / part02 / memory.cc < prev    next >
C/C++ Source or Header  |  1994-09-05  |  11KB  |  364 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               UNT Virtual Machine
  6.  *       Handle real and virtual memory requests and the "drum"
  7.  *
  8.  * One part of the present file implements the Mememory Management Unit,
  9.  * a piece of hardware located between the CPU and the bus and responsible
  10.  * for translation of virtual addresses into the "real" ones.
  11.  * The other part of the present file emulates the physical memory,
  12.  * which is connected to the bus and responds to read/write word
  13.  * requests posted on the bus. The drum is a secondary memory device
  14.  * which is hooked to the physical memory and can transmit sectors
  15.  * of the drum to/from pages of the memory. The drum is assummed to be
  16.  * very fast, so all the drum operations can be thought of as "instant"
  17.  * ones.
  18.  *
  19.  ************************************************************************
  20.  */
  21.  
  22. #pragma implementation
  23. #include "hardware.h"
  24. #include "myenv.h"
  25. #include <std.h>
  26. #include <sys/file.h>
  27.  
  28.  
  29. /*
  30.  *========================================================================
  31.  *            Virtual memory handling
  32.  */
  33.  
  34. MMUContext::MMUContext(void)
  35. {
  36.   page_table_addr = 0;
  37.   page_table_len = 0;
  38.   enabled_address_translation = 0;
  39. }
  40.  
  41. MemoryManagementUnit::MemoryManagementUnit(Memory& phys_memory)
  42.     : memory(phys_memory)
  43. {
  44.   *(Word *)¤t_VA = 0;
  45.   clear_error();
  46. };
  47.  
  48.                 // Perform dump of the translation tables
  49. void MemoryManagementUnit::dump(void) const
  50. {
  51.   if(!enabled_address_translation)
  52.   {
  53.     message("\nVirtual memory is disabled\n");
  54.     return;
  55.   }
  56.   message("\nProcess virtual space is %d pages long\n",page_table_len);
  57.   message("\nAddress range\tAccess\tMapped to    \tWritten\tReferenced\n");
  58.   register int i;
  59.   for(i=0; i<page_table_len; i++)
  60.   {
  61.     const PageTableEntry& pte = 
  62.       *(PageTableEntry*)&memory[page_table_addr+i].contents;
  63.     if( !(pte.any_access || pte.read_only || pte.exec_only) )
  64.       continue;                    // Page isn't allocated
  65.     message("%06o-%06o \t %s\t",Memory::pagesize*i,Memory::pagesize*(i+1)-1,
  66.         pte.exec_only ? "Exec" : pte.read_only ? "Read" : "Any");
  67.     if( pte.valid )
  68.       message("%06o  ",pte.phys_page_no*Memory::pagesize);
  69.     else
  70.       message("Not Mapped ");
  71.     message("\t   %s\t    %s\n",pte.was_written ? "Y" : "N",
  72.         pte.was_ref ? "Y" : "N");
  73.   }
  74.   message("\n");
  75. }
  76.  
  77. Word MemoryManagementUnit::fetch(const Address addr)
  78. {
  79.   Address phys_addr;
  80.   if(enabled_address_translation)
  81.   {
  82.     *(Address *)¤t_VA = addr;
  83.     if(current_VA.page_no >= page_table_len)
  84.       mem_error = WrongVPageNo;
  85.     else if( memory[page_table_addr+current_VA.page_no].out_of_range )
  86.       mem_error = WrongPageTable;
  87.     if( mem_error )
  88.       return 0;
  89.     PageTableEntry& pte = *(PageTableEntry *)&memory[
  90.             page_table_addr+current_VA.page_no].contents;
  91.     if(!pte.any_access && !pte.read_only && !pte.exec_only )
  92.       mem_error = NoAccess;
  93.     else if( !pte.valid )
  94.       mem_error = PageInvalidated;
  95.     else
  96.       current_VA.page_no = pte.phys_page_no,
  97.       pte.was_ref = 1;
  98.  
  99.     if( mem_error )
  100.       return 0;
  101.     phys_addr = *(Address *)¤t_VA;
  102.   }
  103.   else
  104.     phys_addr = addr;
  105.  
  106.   Memory::MemoryAnswer result = memory[phys_addr];
  107.   if(result.out_of_range)
  108.   {
  109.     mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
  110.     return 0;
  111.   }
  112.  
  113.   return result.contents;
  114. }
  115.  
  116.  
  117. Word MemoryManagementUnit::get(const Address addr)
  118. {
  119.   Address phys_addr;
  120.   if(enabled_address_translation)
  121.   {
  122.     *(Address *)¤t_VA = addr;
  123.     if(current_VA.page_no >= page_table_len)
  124.       mem_error = WrongVPageNo;
  125.     else if( memory[page_table_addr+current_VA.page_no].out_of_range )
  126.       mem_error = WrongPageTable;
  127.     if( mem_error )
  128.       return 0;
  129.     PageTableEntry& pte = *(PageTableEntry *)&memory[
  130.             page_table_addr+current_VA.page_no].contents;
  131.     if(!pte.any_access && !pte.read_only && !pte.exec_only )
  132.       mem_error = NoAccess;
  133.     else if( pte.exec_only )
  134.       mem_error = ExecOnly;
  135.     else if( !pte.valid )
  136.       mem_error = PageInvalidated;
  137.     else
  138.       current_VA.page_no = pte.phys_page_no,
  139.       pte.was_ref = 1;
  140.  
  141.     if( mem_error )
  142.       return 0;
  143.     phys_addr = *(Address *)¤t_VA;
  144.   }
  145.   else
  146.     phys_addr = addr;
  147.  
  148.   Memory::MemoryAnswer result = memory[phys_addr];
  149.   if(result.out_of_range)
  150.   {
  151.     mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
  152.     return 0;
  153.   }
  154.  
  155.   return result.contents;
  156. }
  157.  
  158. void MemoryManagementUnit::put(const Address addr,const Word data)
  159. {
  160.   Address phys_addr;
  161.   if(enabled_address_translation)
  162.   {
  163.     *(Address *)¤t_VA = addr;
  164.     if(current_VA.page_no >= page_table_len)
  165.       mem_error = WrongVPageNo;
  166.     else if( memory[page_table_addr+current_VA.page_no].out_of_range )
  167.       mem_error = WrongPageTable;
  168.     if( mem_error )
  169.       return;
  170.     PageTableEntry& pte = *(PageTableEntry *)&memory[
  171.             page_table_addr+current_VA.page_no].contents;
  172.     if(!pte.any_access && !pte.read_only && !pte.exec_only )
  173.       mem_error = NoAccess;
  174.     else if( pte.read_only )
  175.       mem_error = ReadOnly;
  176.     else if( pte.exec_only )
  177.       mem_error = ExecOnly;
  178.     else if( !pte.valid )
  179.       mem_error = PageInvalidated;
  180.     else
  181.       current_VA.page_no = pte.phys_page_no,
  182.       pte.was_ref = 1,
  183.       pte.was_written = 1;
  184.  
  185.     if( mem_error )
  186.       return;
  187.     phys_addr = *(Address *)¤t_VA;
  188.   }
  189.   else
  190.     phys_addr = addr;
  191.  
  192.   Memory::MemoryAnswer result = memory[phys_addr];
  193.   if(result.out_of_range)
  194.     mem_error = enabled_address_translation ? WrongPageTable : OutofRange;
  195.   else
  196.     result.contents = data;
  197. }
  198.  
  199.  
  200. /*
  201.  *========================================================================
  202.  *            Physical Memory handling
  203.  */
  204.  
  205. /*
  206.  *------------------------------------------------------------------------
  207.  *                  Initialization
  208.  */
  209.  
  210. Memory::Memory(void)
  211.     : no_pages((hiaddr+1)/pagesize)
  212. {
  213.   memset(array,0,sizeof(array));        // Clear the memory
  214.   drum_fh = -1;
  215. }
  216.  
  217.  
  218. /*
  219.  *------------------------------------------------------------------------
  220.  *                     Basic memory handling functions
  221.  */
  222.  
  223. #if 0
  224. struct MemoryAnswer Memory::operator [] (const Address addr) //return ans
  225. {
  226.   if( addr > hiaddr )
  227.     ans.out_of_range = 1, contents = array[0];
  228.   else
  229.     ans.out_of_range = 0, contents = array[addr];
  230. }
  231. #endif
  232.  
  233. /*
  234.  *------------------------------------------------------------------------
  235.  *                  Memory Dump
  236.  * Memory contents is printed in rows of 8 words in each.
  237.  * Rows of zeros are skipped. Contents of a memory word is printed in octal.
  238.  */
  239.  
  240. void Memory::dump(const Address from_addr,const Address to_addr)
  241. {
  242.   register Address first_addr = from_addr & ~7;    // Adjust to the 8 word
  243.   register Address last_addr = to_addr & ~7 + 8;// boundary
  244.   if( last_addr == 0 || last_addr > hiaddr+1 )
  245.     last_addr = hiaddr+1;
  246.  
  247.   begin_printing();
  248.   message("\n\n%s\n\n\t\t\tVM UNT Memory Dump\n\n",_Minuses);
  249.   for(; first_addr < last_addr; first_addr += 8)
  250.   {
  251.     register int i;
  252.     int skip = 1;
  253.     for(i=first_addr; skip && i<first_addr+8; i++)
  254.       if( array[i] != 0 )
  255.     skip = 0;
  256.     if( skip )
  257.       continue;                // Skip a line of zeros
  258.     message("%4o:  ",first_addr);
  259.     for(i=first_addr; i<first_addr+8; i++)
  260.       message(" %06o ",array[i]);
  261.     message("\n");
  262.   }
  263.   end_printing();
  264. }
  265.  
  266. /*
  267.  *------------------------------------------------------------------------
  268.  *              Drum operations
  269.  * Note, that the program to be loaded from the drum into the main memory
  270.  * is written started from the 1st drum sector. The 0th drum sector contains
  271.  * the header, starting address of the program, VM memory page to load
  272.  * the program at, and the size of the program in pages (i.e. in drum sectors).
  273.  */
  274.  
  275. void Memory::drum_open(const char * file_name)
  276. {
  277.   drum_fh = open(file_name,O_RDWR,0);
  278.   if( drum_fh < 0 )
  279.     perror("Drum file opening error"),
  280.     _error("Failure to open the drum due to the reason above");
  281.   single_message("Drum file '%s' has been opened",file_name);
  282. }
  283.  
  284.                 // Read one 32 word page from drum
  285.                 // sector to memory physical page
  286.                 // 'pageframeno'
  287. void Memory::drum_read(const int sector_addr, const int pageframeno)
  288. {
  289.   single_message("DRUM: reading from sector %d in memory page %d",
  290.          sector_addr,pageframeno);
  291.   if( sector_addr < 0 || sector_addr >= no_drum_sectors )
  292.     _error("FATAL: drum sector %d is out of range [0,%d]",
  293.        sector_addr,no_drum_sectors-1);
  294.  
  295.   if( pageframeno < 0 || pageframeno >= no_pages  )
  296.     _error("FATAL on drum operation: page frame no %d is out of range [0,%d]",
  297.        pageframeno,no_pages-1);
  298.  
  299.   if( lseek(drum_fh,sector_addr*pagesize*sizeof(Word),0) < 0 )
  300.     perror("FATAL: drum seek failed"),
  301.     _error("System crashes due to the reason above");
  302.  
  303.   if( read(drum_fh,&array[pageframeno*pagesize],pagesize*sizeof(Word))
  304.       != pagesize*sizeof(Word) )
  305.     perror("FATAL: drum read failed"),
  306.     _error("System crashes due to the reason above");
  307. }
  308.  
  309.                 // Write a page of physical memory into
  310.                 // the drum
  311. void Memory::drum_write(const int pageframeno,const int sector_addr)
  312. {
  313.   single_message("DRUM: writing to sector %d from memory page %d",
  314.          sector_addr,pageframeno);
  315.   if( sector_addr < 0 || sector_addr >= no_drum_sectors )
  316.     _error("FATAL: drum sector %d is out of range [0,%d]",
  317.        sector_addr,no_drum_sectors-1);
  318.  
  319.   if( pageframeno < 0 || pageframeno >= no_pages  )
  320.     _error("FATAL on drum operation: page frame no %d is out of range [0,%d]",
  321.        pageframeno,no_pages-1);
  322.  
  323.   if( lseek(drum_fh,sector_addr*pagesize*sizeof(Word),0) < 0 )
  324.     perror("FATAL: drum seek failed"),
  325.     _error("System crashes due to the reason above");
  326.  
  327.   if( write(drum_fh,&array[pageframeno*pagesize],pagesize*sizeof(Word))
  328.       != pagesize*sizeof(Word) )
  329.     perror("FATAL: drum write failed"),
  330.     _error("System crashes due to the reason above");
  331. }
  332.  
  333.                 // Load a program from a drum to
  334.                 // memory starting at physical page
  335.                 // 'pageframeno'
  336. Address Memory::drum_load(const int pageframeno)
  337. {
  338.   if( pageframeno < 0 || pageframeno >= no_pages  )
  339.     _error("FATAL on loading operation: "
  340.        "page frame no %d is out of range [0,%d]",
  341.        pageframeno,no_pages-1);
  342.  
  343.   struct AbsExecHeader {        // Header of the executable abs file
  344.     Word start_addr;                // Starting address
  345.     Word load_page_no;                 // VM page to load the program
  346.     Word size;                    // in pages
  347.   } header;
  348.  
  349.   if( lseek(drum_fh,0,0) < 0 )            // Read the drum header
  350.     perror("FATAL: drum seek failed"),
  351.     _error("System crashes due to the reason above");
  352.   if( read(drum_fh,&header,sizeof(header)) != sizeof(header) )
  353.     perror("FATAL: drum read failed"),
  354.     _error("System crashes due to the reason above");
  355.  
  356.   single_message("Loading a program (size %d, start addr %06o) on %d-th page",
  357.          header.size*pagesize,header.start_addr,header.load_page_no);
  358.   register int i;
  359.   for(i=0; i<header.size; i++)
  360.     drum_read(1+i,header.load_page_no+i);
  361.   return header.start_addr;
  362. }
  363.  
  364.