Instructor: Ding Yuan
Course Number: ECE344

Home
Discussion (piazza)
Lab Documentation
Lab Assignments
Schedule and Lecture Notes
Grades (UofT portal)

Operating Systems

ECE344, Winter 2015
University of Toronto


LAMEbus on MIPS

Summary

  • Physical RAM (up to 508 megabytes) starts at physical address 0.
  • The LAMEbus device mapping area is from physical address 0x1fe00000 to 0x1fffffff.
  • The LAMEbus device mapping area appears at kernel virtual addresses 0xbfe00000 to 0xbfffffff without requiring any kernel setup.
  • Kernels should be linked to be loaded starting at or (generally) closely above virtual address 0x80000000.
Kernel virtual memory map:
Address MIPS
Segment
Region MIPS hardwired address
0xffffffff kseg2 TLB-mappable
kernel space
 
0xc0000000  
0xbfffffff kseg1 LAMEbus mapping area  
0xbfe00000  
0xbfdfffff Boot ROM area
(uncached)
 
0xbfc00180 Exception address if "bootstrap" flag is set
0xbfc00100 UTLB exception address if "bootstrap" flag is set
0xbfc00000 Execution begins here after processor reset.
0xbfbfffff First 508 MB of RAM
(uncached)
 
0xa0000000  
0x9fffffff kseg0 Cached LAMEbus
(not useful)
 
0x9fe00000  
0x9fdfffff Boot ROM area
(cached)
 
0x9fc00000  
0x9fbfffff First 508 MB of RAM
(cached)
 
0x80000080 Exception address if "bootstrap" flag not set.
0x80000000 UTLB exception address if "bootstrap" flag not set.
0x7fffffff kuseg User space  
0x00000000  
Physical memory map:
Address Region
0xffffffff Upper physical RAM (above 508 MB)
0x20000000
0x1fffffff LAMEbus devices
0x1fe00000
0x1fdfffff Boot ROM area
0x1fc00000
0x1fbfffff First 508 MB of physical RAM
0x00000000

Details

The MIPS processor defines four hardwired segments in its virtual address space. It also defines five hardwired addresses that it will jump to at various times. These are listed in the table above.

The segments are:

NameDescription
kseg2Supervisor mode only; TLB-mapped, cacheable
kseg1Supervisor mode only; direct-mapped, uncached
kseg0Supervisor mode only; direct-mapped, cached
kusegUser and supervisor mode; TLB-mapped, cacheable
The mapped segments are mapped via a translation lookaside buffer (TLB) with software refill. The direct-mapped segments are mapped (without use of the TLB) both to the first 512 megabytes of the physical memory space.

Three of the hardwired addresses (the ones used for system initialization) are 4 MB below the top of kseg1. The other two are at the bottom of kseg0. This means that, of the first 512 megabytes of physical memory space, at least part of the top 4M must be ROM, and the very bottom must be RAM. This was clearly designed in an era where 512 megs of memory was an unthinkably large amount.

We put the first 508 megs of physical RAM starting at physical address 0. After this we reserve 2 megabytes for a boot ROM; after that we put the 2-megabyte LAMEbus mapping area. Then physical RAM resumes again at the 512-meg mark. Thus, if the RAMSZ register reports 512 megs of RAM, it will appear from 0x0 to 0x1fbfffff and then from 0x20000000 to 0x203fffff.

(Note that the current implementation will not let you configure anywhere near 512 megs of physical RAM, and does not actually have a boot ROM, just 2 megs of empty space. If you get an exception before switching off the "bootstrap" flag, the system will hang trying to execute from nonexistent memory. This is suboptimal and may be corrected in a future release.)

As a result of all this, the best place to load a kernel is starting at 0x80001000, the first page after the page containing the hardwired exception addresses. Because of the way ELF executables work and because of the way linkers work, trying to create a kernel image to load at 0x80000000 that has the exception entry points in exactly the right place is highly impractical. The best bet is to write position-independent code for the entry points and copy it into place during kernel initialization.

Note that System/161 does not implement a cache simulator; all memory accesses go straight through to memory. This is important, because the MIPS architecture does not guarantee synchronization between the instruction and data caches. On a real MIPS, after performing any operation that involves writing code to memory and then executing it later, one must manually flush the instruction cache. This is painful to implement. If you are only running on System/161 and never intend to run on a real MIPS, you can avoid actually implementing this code, though you should stub it out and insert calls to it in the necessary places in case you change your mind later.

This is also a concern for hardware devices that may do DMA into cached regions of memory. However, LAMEbus devices do not do DMA (instead they have memory-mapped buffers) and the LAMEbus mapping area is meant to be accessed through the uncached hardwired segment. It also appears in the cached hardwired segment, but as cached memory access is worse than useless for device registers, this area should not be used.

Kernel loading on MIPS takes place exactly as described for the general case. Assuming the kernel is linked to run at 0x80001000, it will be loaded into physical memory starting at 0x00001000 (which appears at virtual address 0x80001000) and control will be transferred to the kernel's entry point in virtual memory as recorded by the linker.

The kernel arguments are assembled into a single null-terminated string which is stored at the top of physical memory. The address of this string is passed in the first argument register (a0, register 4). The stack pointer is initialized to point near the top of physical memory, so it can be used (growing down as normal) for scratch space during kernel initialization if necessary.

Because the MIPS has a 32-bit memory bus, all registers (all LAMEbus device registers are 32-bit) can be read or written atomically in a single instruction.