Is MMU Required for Running Embedded Linux?

Scan to FollowLearn Embedded Together, learn and grow together

Is MMU Required for Running Embedded Linux?

Why is MMU Needed?

We know that applications cannot access memory arbitrarily. Allowing applications to directly access physical memory would be very dangerous, as all contents of the computer’s memory would be completely exposed.

This is where the MMU comes in. The MMU, or Memory Management Unit, allows applications to access virtual memory, which is then translated into physical memory through the MMU. The physical memory corresponds to the actual addresses on the physical storage disk. A detailed explanation of the MMU.

The mainline Linux code requires the MMU mechanism to run normally.

However, it is also possible to run Linux kernel code without an MMU, but this requires trimming and configuration, with debugging being the most challenging part.

The MMU module is generally an internal component of the CPU, although there are cases where an MMU is not present.

If you want to run Linux kernel code without an MMU, you might want to look at uClinux.

What is uClinux?

The term uClinux consists of ‘u’ for Micro, meaning small, and ‘C’ for Control, so uClinux stands for Micro-Control-Linux, which can be understood as “a Linux system designed for the microcontroller domain”.

Differences Between uClinux and Linux

  • No virtual memory management unit (MMU)
  • Cannot increase process stack at runtime
  • No support for paging
  • Executable programs are not ELF, but flat
  • Cannot use fork, but uses vfork
  • RAMDISK

uClinux is an embedded Linux operating system designed for control applications, derived from the Linux 2.0/2.4 kernel, inheriting most features of mainstream Linux. It is suitable for microprocessors/microcontrollers that do not have a Memory Management Unit (MMU). The lack of MMU support is the fundamental difference between uClinux and mainstream Linux.

For uClinux, its design targets processors without an MMU, which cannot utilize the processor’s virtual memory management techniques. uClinux still employs memory paging management, where the actual memory is paged at system startup. When loading applications, the program is loaded in pages. However, due to the absence of MMU management, uClinux adopts a physical memory management strategy.

Memory access in uClinux is direct, meaning all addresses accessed by programs are actual physical addresses. The operating system does not protect memory space, and all processes effectively share a single runtime space.

Before a process executes, the system must allocate enough contiguous address space for the process, which is then fully loaded into contiguous main memory.

Memory Protection

Operating without memory protection can lead to the following results:

Even if a non-privileged process calls an invalid pointer, it can trigger an address error, potentially causing the program to crash or even leading to system hangs. Clearly, code running on such a system must be carefully programmed and thoroughly tested to ensure robustness and safety.

For standard Linux, running different user programs without memory protection would significantly reduce system security and reliability; however, for embedded uClinux systems, since the programs are often hard-coded before leaving the factory, there is no risk of harmful program intrusion, so as long as the application has undergone thorough testing, the probability of issues can be kept within a limited range.

Virtual Memory

The absence of virtual memory primarily leads to the following consequences:

First, processes loaded by the kernel must be able to run independently of their location in memory. One way to achieve this is to fix the program’s base address once it is loaded into RAM; another way is to generate code that uses only relative addressing (known as Position Independent Code, or PIC). uClinux supports both modes.

Secondly, it must address memory allocation and deallocation issues in a flat memory model. Highly dynamic memory allocation can lead to memory fragmentation and may exhaust system resources. For applications that use dynamic memory allocation, one way to enhance robustness is to replace malloc() calls with a preallocated buffer pool.

Since uClinux does not use virtual memory, page swapping in and out of memory is not implemented, as it cannot guarantee that pages will be loaded into the same location in RAM. On standard computers, the operating system allows applications to use more memory space than physical memory (RAM), often achieved by setting up a swap partition on the hard drive. However, in embedded systems, FLASH memory typically replaces hard drives, making efficient memory page swapping difficult, thus limiting the allocable space for running applications to no more than the system’s RAM.

Note: Multitasking is not affected. Some older, widely used network daemon programs that heavily rely on fork() will indeed need modification. Since child processes run in the same address space as the parent process, in some cases, the behavior of both processes may need to be adjusted.

Many modern programs rely on child processes to perform basic tasks, allowing the system to maintain an “interactive” state even under heavy process load. These programs may require substantial modifications to accomplish the same tasks under uClinux. If a critical application heavily depends on such a structure, it will have to be rewritten.

For example, consider a simple network daemon that heavily uses fork(). This daemon continuously listens on a well-known port (or socket) for network clients to connect. When a client connects, the daemon provides it with new connection information (a new socket number) and calls fork(). The child process then connects with the client on the new socket, while the parent process is freed to continue listening for new connections.

uClinux has neither an automatically growing stack nor a brk() function, so user-space programs must use mmap() to allocate memory. For convenience, the malloc() implemented in the C library of uClinux is essentially an mmap(). During compilation, the stack size of the program can be specified.

Finally, the target processor of uClinux lacks hardware units for memory management, necessitating changes to the Linux system interface.

The most significant difference is the absence of fork() and brk() system calls. Calling fork() creates a child process by duplicating the process. In Linux, fork() is implemented using copy-on-write pages. Due to the lack of an MMU, uClinux cannot fully and reliably duplicate a process, nor can it access copy-on-write.

To compensate for this deficiency, uClinux implements vfork(). When the parent process calls vfork() to create a child process, both processes share their entire memory space, including the stack.

The child process either replaces the parent process (at which point the parent process is already sleeping) until the child process calls exit() to terminate, or it calls exec() to execute a new process, which will load the executable file. Even if this process is merely a copy of the parent process, this cannot be avoided.

After the child process executes exit() or exec(), it uses wakeup to wake the parent process, allowing the parent process to continue execution.

Changes in General Kernel Architecture:

In the release of uClinux, the /linux/mmnommu directory replaces the /linux/mm directory. The former is a modified memory management subsystem that removes MMU hardware dependencies and provides basic memory management functions within the kernel software itself.

Many subsystems need to be modified, added, or rewritten. The kernel and user memory allocation and deallocation processes must be re-implemented, and support for transparent interaction/page scheduling has been removed. The kernel has added support modules for “kernel-independent code (PIC)” and uses a new binary target code format called flat format to support PIC (which has a very compact header).

The kernel also provides a program loading module that supports ELF format to accommodate executable programs with fixed base addresses. Each mode has its advantages and disadvantages; traditional PIC runs faster and has compact code, but there are size limitations on the code.

For example, the 16-bit relative jump limitation of the Motorola 68K architecture restricts PIC programs to a maximum size of 32KB, while programs using the fixed base address method have no size limitations, but loading them into the kernel incurs more system overhead.

For kernel developers, uClinux is essentially no different from Linux, with the only distinction being the inability to utilize memory management provided by the MMU. In fact, this does not affect the kernel.

All standard executable file formats under Linux are not supported in uClinux, as these formats also utilize some features of virtual memory. uClinux uses a different flat format, which is a simple and efficient executable file format that contains executable code and data, along with some relocatable information needed to load the executable file into any memory location.

Conclusion

When porting applications to uClinux and writing your own code, we will always focus on the following features:

1. When configuring, if possible, select –disable-shared and –enable-static.

2. Change all instances of fork() in the source code to vfork();

3. In the Makefile, add -Wl,-elf2flt to the cross-compiler and compilation options, as well as the linking options. Although this is just a linking option, I still carefully specified this option in LDFLAGS, CFLAGS, and even CC.

This option converts the ELF format into the FLAT format recognized by uClinux. During this conversion process, we cannot use strip to remove some information from the ELF file, and we cannot use the -O2 option to optimize the code. Removing certain information may lead to issues with the final generated FLAT format file.

Original Article:https://blog.csdn.net/linux12121/article/details/82833607

Source from the internet, copyright belongs to the original author. If there is any infringement, please contact for deletion.

Is MMU Required for Running Embedded Linux?

Scan to join a high-quality embedded group

Is MMU Required for Running Embedded Linux?

Follow me [Learn Embedded Together], learn and grow together.

If you find the article useful, click “Share”, “Like”, or “View”!

Leave a Comment