Linux on Cortex-M3
Cortex-M3 is an ARMv7-M CPU targeting the microcontrollers space. It supports the Thumb-2 instruction set, Memory Protection Unit (MPU but no MMU), integrated Nested Vectored Interrupt Controller (NVIC), timer.
Cortex-M3 supports two operating modes - Thread and Handler. The Thread mode can be privileged or unprivileged. The Handler mode is always privileged. At reset, the CPU starts in privileged Thread mode and switching to the Handler mode is done via an interrupt, exception or an explicit system call (the SVC instruction).
Cortex-M3 has two stacks - the main stack and the process stack. The Thread mode can use either the main or the process stacks. The Handler mode always uses the main stack. When taking an exception, the CPU automatically saves the state (R0-R3, R12, LR, ReturnAddress, xPSR) on the main stack. When returning from an exception, simply loading the exception LR into PC causes the state previously saved on the stack to be restored. Note that interrupts are not automatically disabled or enabled on exception entry or exit.
For more information, see the Cortex-M3 Technical Reference Manual and the ARMv7-M Architecture Reference Manual on the http://infocenter.arm.com/
The Cortex-M3 Linux patches are now part of the ARM Embedded Linux kernel available from:
Alternatively, the Git tree hosting the Linux patches is available from (currently based on Linux 2.6.33)
Individual Cortex-M3 patches can be extracted from the Git tree above.
The port currently supports Cortex-M3 on the the Microcontroller Prototyping System:
The filesystem consists of a cut-down version of busybox with minimal functionality. A more complex Thumb-2 filesystem can be used if sufficient RAM is available on the board. Busybox 1.10.1 (newer version can be used) is available from:
Building the Linux kernel
For building the Linux kernel, a recent toolchain with support for ARMv7-M is required. One can be downloaded from CodeSourcery's website:
To build the kernel, follow the steps below:
- Using the source code snapshot mentioned above, copy the attached .config and initramfs-list-min files in the top directory of the kernel tree.
- Modify the CONFIG_INITRAMFS_SOURCE variable in the .config file to point to the initramfs-list-min file
- Modify the initramfs-list-min file to point to the built busybox tool (see below for details about building busybox)
- Build the kernel (do not build the compressed image if the amount of RAM is small):
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- Image
The Image is available in the arch/arm/boot/ directory.
A Pre-built busybox
file is attached to this page.
For building busybox (or other applications), a compiler supporting uClinux and ARMv7-M is needed. One can be downloaded from CodeSourcery's website:
In the extracted busybox source directory copy the attached .config
file and create the arch/arm/Makefile file containing the compiler details:
CROSS_COMPILE = arm-uclinuxeabi-
CFLAGS += -march=armv7-m -mthumb -Wl,-elf2flt=-s -Wl,-elf2flt=16384
To modify the configuration:
make ARCH=arm menuconfig
To compile busybox:
The busybox file is created in the top directory. Use the path to the built busybox in the initramfs-list-min file.
Running Linux on RealView EB + Cortex-M3
The current method for running Linux on RealView EB + Cortex-M3 is to load the Image file with RVD at 0x20008000 and set the appropriate registers. Because there is no boot monitor to initialise the board, the CPU is initially stuch in a Hard Fault. The following commands can be copied to an RVD script to run Linux:
;; Ensure the Thumb mode and no current exception
setreg @XPSR = 0x01000000
;; Reset any faults (Application Interrupt and Reset Control Register)
setmem/w 0xe000ed0c = 0x05fa0002
setmem/w 0xe000ed28 = 0xffffffff
;; UART setup - RealView EB
;; ibrd - 38400 (24MHz clock)
setmem/w 0x40009000 + 0x24 = 39
setmem/w 0x40009000 + 0x28 = 4
;; cr_h - 8N1
setmem/w 0x40009000 + 0x2c = 0x60
;; cr - hardware flow control
setmem/w 0x40009000 + 0x30 = 0x0301
setreg @R0 = 0
setreg @R1 = 827
setreg @R2 = 0
setreg @R3 = 0
setreg @PC = 0x20008000
;; clear the first page
fill 0x20000000..0x20000fff = 0
setmem/w 0x20000100 = 2
setmem/w 0x20000104 = 0x54410001
;; ATAG_CMDLINE (size (1024 + 8) / 4)
setmem/w 0x20000108 = 258
setmem/w 0x2000010c = 0x54410009
;; command line
setmem/b 0x20000110 = "init=/bin/sh console=ttyAMA0 mem=2M"
Details of the Linux port
The Linux kernel used as a base for Cortex-M3 must support MMU-less CPUs and be compilable to the Thumb-2 instruction set. Patches supporting this are already implemented and available via the above links.
The base patch for Cortex-M3 adds the corresponding arch/arm/mm/ files and several #ifdef's around the kernel for cases where the Cortex-M3 functionality is different (no CP15 register, different xPSR etc.).
The register definitions in include/asm-arm/ptrace.h were reordered to benefit from the automatic state saving on exception entry.
was removed and
added to hold the value of the exception LR register (which has a different meaning from the ReturnAddress).
Linux initially boots in the privileged Thread mode but it is switched to Handler mode in proc-v7m.S via an SVCall during the boot process. After this, the kernel start-up code and kernel threads run in Handler mode (using the main stack). User-space processes run in unprivileged Thread mode using the process stack.
Linux requires two stack for a user-space thread - a kernel stack (main stack on Cortex-M3) and a user stack (process stack on Cortex-M3). Kernel threads only require one stack (main stack on Cortex-M3). Context switching is performed by switching the kernel stacks corresponding to the current and new thread. If the scheduled-in thread is a user thread, the user stack is automatically activated and the state restored when returning from kernel (returning from Handler to Thread mode).
To simplify the exception handling mechanism, the decision was made to run kernel threads in Handler mode with SVCall priority. The disadvantage of this approach is that kernel preemption is not possible since the Handler mode cannot be preempted by the Thread mode. Alternatively, the exception handling code can be improved so that it only runs for a short time and switches to the privileged Thread mode for executing the rest of the kernel code. ARMv7-M allows the interrupts to remain disabled when returning from an exception handler. The exception handling code would become a micro-scheduler responsible for switching between kernel and user applications and passing arguments between the two.
The main exception code is implemented in the arch/arm/kernel/entry-v7m.S file. It contains the exception vector table together with handlers for interrupts and PendSV (other exceptions are, for now, considered fatal and not handled). This file also contains the
function responsible for context switching between two threads.
The complete register state saving and restoring is handled by the
macros defined in entry-header.S. The fast_exit macro is used when returning from an interrupt handler while the slow_exit one is used when returning from a system call or PendSV. The interrupted mode is detected from the value of the exception LR register. This is especially important when returning to user space for setting the correct process stack.
Context switching can only occur during SVCall or PendSV handling. These exceptions have the same priority but lower than interrupts to allow IRQ handling during system call processing. If the current task needs to be rescheduled after an interrupt handling, the
code raises a PendSV which will be taken after the current handler completes.
Nested Vectored Interrupt Controller
The NVIC support is pretty similar to the GIC one. The patch adds the standard Linux functions for masking, unmasking and acknowledging interrupts. The IRQ number that generated an interrupt is read from the IPSR register in the
code in entry-v7m.S.
RealView EB + Cortex-M3
The Cortex-M3 hosted in the FPGA of RealView EB has a different memory map from standard EB board. The patch modifies the include/asm-arm/arch-realview/board-eb.h and platform.h files accordingly and adds the NVIC initialisation call.
- .config: Linux on Cortex-M3 configuration file
- busybox: Pre-built busybox for ARMv7-M
- 01 Jul 2008