What is Non-MMU or MMU-less Linux ?
by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)
In olden days, embedded system is always assumed as equivalent to microcontroller
based system design. On the other hand, the development of RISC based microprocessor
is still not mature in terms of technology and production cost. Hence, in those days,
MMU is something luxury to be implemented in both microcontroller or microprocessor.
However, in nowadays, MMU is almost a built-in feature in majority of RISC processors.
Of course, some low-end RISC processor such as ARM-M4 does not come with MMU, but it
is almost a legacy. In fact, the unit price of a standard RISC processor such as
ARM-A5 is almost closed to $5, therefore, there is no more substantial reason to use
those low-end RISC processors which are without MMU. Yes, this is from the angle of
embedded system, however, the existence of MMU in microcontroller is still an
argument. Due to the demand of low-cost in microcontroller, it is normally with much
lower clock speed, memory space support, number of register, and etc. So, it is a
little bit unreasonable to implement MMU in microcontroller. On the other hand, from
software perspective, code reusability is really a trend in reducing the time-to-market
of a product. Besides, the complexity of its features are getting higher and higher.
Try to imagine, is it a standard feature for an embedded product to access remote
shared folder which is hosted in a PC within the same network ? Is it a daunting
process to develop NFS or SAMBA by your own again and again in different platform ?
Yes, it is really terrible, and that's why we need a linux kernel. With the linux
kernel, then it is up to your cross-compilation skill to migrate those useful modules
such as FUSE, SAMBA, NFS and USB into your own platform in a short period of time.
Well, the discussion come to linux kernel now. As what we know, linux kernel is
designed for PC based platform, not embedded platform. In other words, linux kernel
expects to have MMU to run in proper. However, due to the power of open source, it
has been modified to run in non-MMU platform, and it is known as uClinux. In uClinux,
the memory address is directly mapped to the physical address, and there is no
protection among different processes. So, it is very possible for a process to
corrupt another process and causes the system crash. Anyway, let us assume the
uClinux itself is robust to run, and we focus our discussion in user application.
Majority of the user applications use fork() to spawn new child process. In the
process of fork(), the parent process will be duplicated to the new process.
After that, both of the process with run together. However, in most of the times,
the child process will eventually call execve(), and pass the process environment
to the new program. Yes, such action is really wasting the precious memory space.
So, in recent version of linux kernel, the fork() process has been rectified to
make use the concept of copy-on-write. Thus, the parent process will not be forced
to duplicate over to the child process, unless any write action being detected. Fine,
the fork() process is much optimized now. But, in order to perform copy-on-write,
MMU is necessary. So, fork() must be changed to support non-MMU platform. In uClinux,
vfork() is the alternative. With vfork(), the child process will borrow the address
space of the parent process. While the child process is running, the parent process
will be suspended until the child process calls _exit() or execve(). In this case,
only one process is running at a specific time. But, since they are both running in
the same process space, it is easily for a child process to corrupt the structure of
the parent process. The blame is reasonable because majority of the open source
applications are developed under the environment with MMU. In fact, they are valid
for "full" linux, but not for such "customized" linux. So, in order to run an
existing open source application in uClinux, heavy and serious modification is needed
for the attempt. Well, this is a very subjective issue to justify either is it worth
to spend times and resources in doing such modification. However, for the case of
developing new application, then uClinux is really a good choice. By implementing the
codes in proper, it should work well in uClinux. In fact, we suppose to say that the
codes can run in all uClinux compatible platform with minor modification such as the
redefinition of I/O addresses and etc. Anyway, such so called non-MMU or MMU-less
linux is really a legacy in embedded system. Instead, with a cost-effective RISC
processor in mid-range feature such as ARM-A8, it is no problem at all to support
full linux kernel. So, with full linux kernel, it is comfortable to perform cross
compilation of open source applications as usual again, and let them to work together
with our own codes.