Physical memory map:
Address MIPS
SegmentRegion MIPS hardwired address 0xffffffff kseg2 TLB-mappable
kernel space0xc0000000 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
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
The segments are:
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.
Name Description kseg2 Supervisor mode only; TLB-mapped, cacheable kseg1 Supervisor mode only; direct-mapped, uncached kseg0 Supervisor mode only; direct-mapped, cached kuseg User and supervisor mode; TLB-mapped, cacheable
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.