Memory on MIPS-based processors is broken into several segments, consuming the entire 32-address space. These segments are arranged as follows:
- User Segment (USEG), 2 GB mapped and cached, addresses 0x0000 0000 through 0x7FFF FFFF
- Kernel Segment 0 (KSEG0), 512 MB unmapped and cached, addresses 0x8000 0000 through 0x9FFF FFFF
- Kernel Segment 1 (KSEG1), 512 MB unmapped and uncached, addresses 0xA000 0000 through 0xBFFF FFFF
- Kernel Segment 2 (KSEG2), 1 GB mapped and cached, addresses 0xC000 0000 through 0xFFFF FFFF
Note that the WRT54GL only has 16 MB of main memory, so a 1-1 mapping is not be available above 0x..FF FFFF.
The user segment of memory, or USEG, is the range of memory addresses from 0x0000 0000 through 0x7FFF FFFF. This memory is both mapped and cached, meaning that any attempt to access memory within this range will result in the hardware consulting the memory manager prior to access. Note that any attempted access in this range must with the CPU privilege level set to user mode (i.e. ) or the processor must be in the exception state with the error level bit set (i.e. ). In the latter case, all mappings turn into 1-1, so directly accessing these address is not recommended.
Under normal operation, when an address in this memory range is accessed, the processor will query the memory management unit is consulted for a mapping. In turn this will ask the translation lookaside buffer (TLB), and if no mapping is found cause a TLB load or store exception. When this exception occurs, the operating system is consulted and should write the correct mapping to the TLB and return from the exception handler.
User Segment under Xinu
Embedded Xinu has basic memory management as of the 2.0 release (stored in the mem/ directory). During initialization, the kernel allocates some amount of memory (defined in
xinu.conf as UHEAP_SIZE) to act as the user memory heap. Once this memory is initialized, calls to
free will use the user heap for memory allocation and automatically insert mappings into the system page table. All mappings are 1-1 since there is no backing store for a virtual memory subsystem, though it would be possible to provide each thread with a private address space this requires lots of memory overhead.
Exception code to handle TLB faults is in the
tlbMissHandler function and simply performs a lookup of the faulting address in the system page table, checks to see if it is valid and in the correct address space, and inserts the mapping in the TLB hardware.
While the first part of memory is dedicated to the user segment, the remainder is the kernel segment. Unlike the user segment, the kernel segment is sub-divided into three segments with different memory access properties. Note that these properties can be very important if you are dealing with device drivers and/or hardware that uses direct memory access (DMA) because there may be caching considerations.
- KSEG0 uses unmapped and cached memory accesses,
- KSEG1 uses unmapped and uncached memory accesses, and
- KSEG2 uses mapped and cached memory accesses.
Kernel Segment 0
This segment exists from memory address 0x8000 0000 to 0x9FFF FFFF and is cached but remains unmapped (beyond the simple address - 0x8000 0000 mapping).
The first 0x1000 bytes of this segment are reserved system space and contains small amounts of code for the interrupt handler. When an interrupt or exception occurs, the MIPS processor will jump to code located at 0x8000 0180, expecting to find handler code at that location. For safety reasons that code can only consume 0x20 bytes of memory (enough to jump to a safer, more robust handler). Embedded XINU takes advantage of the space immediately after the end of interrupt handling code by loading entry vectors for the various interrupts and exceptions for speedy lookup.
After the reserved system space it is safe to load generic code, XINU code is loaded to 0x8000 1000 and begins execution at the same offset. XINU code begins with the text segment, followed by the data and BSS segments. After the compiled image is loaded into RAM, XINU allocates a specific amount of memory for the kernel stack immediately after the BSS segment. Once the kernel stack has been setup, XINU initializes the heap beginning directly above the kernel stack and continuing until the end of physical memory (0x80FF FFFF).
Kernel memory allocation will take memory addresses from the heap initialized in this segment.
Kernel Segment 1
Beginning at 0xA000 0000 and ending at 0xBFFF FFFF, kernel segment 1 is both unmapped and uncached memory. This means that any memory references will leave the processor and travel to the memory bus to get the most up-to-date data available. While this may be a slow process, this section of memory is important to direct memory access (DMA) devices, which may have volatile data existing in the memory system. This can be used to access kernel memory from addresses 0xA000 0000 to 0xA0FF FFFF but more importantly can be used to access I/O mapped devices on the system.
These devices appear to begin at 0xB800 0000 with the Broadcom I/O controller on IRQ 3 which holds the GPIO registers from 0xB800 0060 to 0xB800 006F and the two UART ports from 0xB800 0300 to <0xB800 0307/tt> and from <tt>0xB800 0400 to 0xB800 0407.
From there, devices are seperated by 0x1000 bytes beginning with the Broadcom Ethernet 47xx (possibly 4401) device at 0xB800 1000 on IRQ 4. The MIPS 32 CPU on IRQ 5 is located at 0xB800 2000, a Broadcom USB controller on IRQ 6 is located at 0xB800 3000, a DD SDRAM Controller on IRQ 3 is found at 0xB800 4000, the Broadcom Wireless LAN controller on IRQ 2 is at 0xB800 5000, and finally the Broadcom 47xx Robo Switch core on IRQ 3 responds to addresses beginning with 0xB800 6000.
After these devices is Flash memory which begins at 0xBC00 0000 and is 4 megabytes in size (lasting until 0xBC3F FFFF).
Kernel Segment 2
The last segment of MIPS memory is located at 0xC000 0000 and ends at 0xFFFF FFFF, giving the kernel one gigabyte of fully mapped memory. Similar to the user segment, the Embedded XINU team has not looked extensively into the usefulness of this segment.
Unlike other devices on the system Flash memory is fully mapped, meaning it is possible to access every location of the four megabyte range by simply dereferencing a pointer between 0xBC00 0000 and 0xBC3F FFFF. Within Flash memory there are a number of notable addresses:
- 0xBC00 1000: Generic backup NVRAM variables (if proper variables become corrupt, these are the values that will replace them).
- 0xBC00 1E00: "True" MAC address of device, this is the mac address CFE will use during the boot process. Once the system is booted, the MAC address is not necessarily the same as the value stored here. The value is stored in ASCII as 6 colon separated octets for a total of 17 bytes.
- 0xBC00 1F00: CFE Boot Version variable ("v3.7")
- 0xBC00 2000: CFE code begins
- 0xBC03 F400: Unique device ID, this is loaded into NVRAM variables as eou_device_id
- 0xBC03 F408: Private key for device, also loaded into NVRAM variables as eou_private_key
- 0xBC03 F508: Public key for device, also loaded into NVRAM variables as eou_public_key
- 0xBC04 0000: XINU code, gzipped raw binary prefixed with a TRX header containing the length and a checksum among other data.
- 0xBC06 0000: Beginning of XINU file system
- 0xBC3F 8000: NVRAM variables are stored here, prefix with a padded length and checksum among other data for a 20 byte header. Each variable is stored as a name=value pair (as ASCII data) and separated by a single null character.
Sweetman, Dominic. See MIPS Run. San Francisco: Morgan Kaufmann Publishers, 2007.