De-mystifying User and Kernel Memory on the PIC32MK

Last modified by Microchip on 2023/11/09 09:00

Background

The MIPS® memory system is a unified architecture designed to be used by both microcontrollers (MCUs) and microprocessors (MPUs).

MPU systems commonly run an operating system and may have complex multi-layer data caches. At runtime, applications are loaded into an MPU's program memory and executed. Some of these applications may not have been fully tested by the system vendor. A poorly, or maliciously, written application accessing system resources, such as the MPUs configuration registers, can cause problems. MPU system vendors have a vested interest in limiting the scope of the system resources accessed by third-party application programs.

Unlike MPUs, MCUs rarely have untested external applications loaded at run-time. MCUs applications are typically developed and verified before they are programmed into the MCU's non-volatile Flash memory. In order to fully utilize an MCU's integrated peripherals, applications expect unfettered access to system resources such as the Special Function Registers (SFRs). MCU system vendors need a memory architecture that allows application programs wide access to system resources.

The MIPS memory architecture restricts resource access for some applications while allowing complete access for other applications.

Basics

The specific examples and address ranges used on this page are for the PIC32MK1024MCF. Please refer to the datasheet of the PIC32M device you are using.

Application programs, data memory, and SFRs on PIC32M devices exist in physical memory. The physical memory has an address range of 512 MB.

PIC32MK1024MCF Physical Memory Map

Figure 1.1: PIC32MK1024MCF Physical Memory Map

While PIC32M programs are executed from physical memory they are accessed through virtual memory.

There are 4 GB of addressable virtual memory on a PIC32MK. Virtual memory is split into a pair of 2 GB memory spaces: Kernel space and User space. Kernel space begins at location 0x800000 and consists of 4 separate 512 MB segments (KSEG0, KSEG1, KSEG2, and KSEG3), User space consists of a single 2 GB segment (KSUEG) and is located at address 0x000000. The virtual segments are mapped to areas of the physical memory using fixed mapping translation (FMT).

Virtual Memory Mapping

Figure 1.2 Virtual Memory Mapping

There is intentional over-mapping of virtual memory segments to the physical memory. Each byte of physical memory is accessible from multiple virtual memory segments.

It's All About the Virtual Memory!

The runtime properties of physical memory are determined by the virtual memory address used to access the memory location. Each of the virtual segments imposes a different set of attributes on physical memory. The calling segment determines the following:

  • Whether or not the physical memory is visible to the CPU
  • The range of addresses which can be accessed by any instruction executed in physical memory
  • Whether or not data cache is used to access the memory.

Directives are placed in the source code to instruct the compiler to map a function, interrupt vector, or data element to a particular memory segment. If no directives are added to the code, the compiler's default is to place all user-generated code in KSEG0.

Back to top

Kernel Space

At reset, only Kernel Space is available.

On PIC32MK devices only KSEG1 and KSEG0 are available. KSEG3 is not implemented and KSEG2 is reserved for JTAG boundary scan (check the data sheet of the device you are using).

KSEG0 and KSEG1 map on PIC32MK1024MCF

Figure 1.3: KSEG0 and KSEG1 map on PIC32MK1024MCF

KSEG1 and KSEG0 have identical address mapping. KSEG0 and KSEG1 allow programs to access all physical memory locations and SFRs. These segments differ only in that KSEG0 accesses go through cache memory and KSEG1 bypasses the cache.

There are several reasons an application may wish to bypass the cache.

  1. Cache Coherency - At startup, some applications require the SFRs to be initialized in a specific order. Using a cache to update multiple SFRs may cause inadvertent, cache flushes changing the order in which the SFRs are updated. While cache-related start-up problems are rare, the compiler ensures that the cache is bypassed during system started by addressing the startup code through KSEG1.
  2. Run-Time Cache Thrashing - In a multi-tasking system, several tasks share the cache buffer. At any instant, the cache has small amounts of data from each of the active tasks. If one of the tasks consistently accesses large amounts of data the entire cache flushes each time that task is run. This will force the cache to be reloaded when the other tasks re-access their data. In a typical round-robin multitasking MCU system, this constant cache flushing impedes system performance. To solve this dilemma, slower data-intensive tasks, such as CAN bus transactions can be directed to run from KSEG1.

Back to top

User Space

Programs running from KUSEG do not have access to the MCU's SFRs or boot Flash memory. The memory locations for these resources are not mapped. Any attempted access to one of these areas from KSUEG will result in a system exception. The addressable areas of program and data memory that are available to KUSEG are configured at runtime.

Before applications can be run from the user space, a program run in the kernel space must do the following:

  • Make the user space visible by setting UM in the status register (CP0 register12).
  • Configure the memory addresses to be accessible in user space by setting the BMX control registers (BMXDUDBABMXDUPBABMXPUPBA, and BMXDKPBA).

See section 3 of the "PIC32 Reference Manual" for the specific details and examples for configuring user space.

Back to top

Putting it All Together

  • Virtually all PIC32 applications run in the default Kernel mode. User mode is rarely used for PIC32 applications.

  • If data cache exists on the PIC32 being used, MPLAB® XC32 C/C++ Compiler's default linker script will cause the startup code to be placed in KSEG1.
  • If no data cache exists on the target device, such as with the PIC32MK, the startup code is put in KSEG0.
  • The default segment for main() is KSEG0.

Back to top