1------------- 2--- Intro --- 3------------- 4 5Linux running on processors without a memory management unit place certain 6restrictions on the userspace programs. Here we will provide some guidelines 7for people who are not familiar with such systems. 8 9If you are not familiar with virtual memory, you might want to review some 10background such as: 11 http://en.wikipedia.org/wiki/Virtual_Memory 12 /usr/src/linux/Documentation/nommu-mmap.txt 13 14---------------------------- 15--- No memory protection --- 16---------------------------- 17 18By virtue of every process getting its own virtual memory space, applications 19are protected from each other. So a bad memory access in one will not affect 20the memory of another. When processors forgo virtual memory, they typically 21do not add memory protection back in to the hardware. There are one or two 22exceptions to this rule, but for now, we'll assume no one supports it. 23 24In practical terms, this means you cannot dereference bad pointers directly 25and expect the kernel to catch and kill your application. However, you can 26expect the kernel to catch some bad pointers when given to system calls. 27 28For example, this will "work" in the sense that no signal will be sent: 29 char *foo = NULL; 30 foo[0] = 'a'; 31 foo[1] = 'b'; 32 33However, the kernel should return errors when using "standard" bad pointers 34with system calls. Such as: 35 char *foo = NULL; 36 write(1, foo, 10); 37 -> kernel will return EFAULT or similar 38The other bad pointer you can rely on in your tests is -1: 39 char *foo = (void *)-1; 40 read(0, foo, 10); 41 -> kernel will return EFAULT or similar 42 43Otherwise, no bad pointer may reliably be tested, either directly or 44indirectly via the kernel. This tends to be a large part of the UCLINUX 45ifdef code that shows up in LTP. 46 47---------------- 48--- No forks --- 49---------------- 50 51The ubiquitous fork() function relies completely on the Copy On Write (COW) 52functionality provided by virtual memory to share pages between processes. 53Since this isn't feasible without virtual memory, there is no fork() function. 54You will either get a linker error (undefined reference to fork) or you will 55get a runtime failure of ENOSYS. 56 57Typically, fork() is used for very few programming paradigms: 58 - daemonization 59 - run a program 60 - parallelism 61 62For the daemonization functionality, simply use the daemon() function. This 63works under both MMU and NOMMU systems. 64 65To run a program, simply use vfork() followed by an exec-style function. 66And change the error handler in the child from exit() to _exit(). This too 67works under both MMU and NOMMU systems. But be aware of vfork() semantics -- 68since the parent and child share the same memory process, the child has to be 69careful in what it does. This is why the recommended construct is simply: 70 pid_t child = vfork(); 71 if (vfork == 0) 72 _exit(execl(....)); 73 74For parallelism where processes use IPC to work together, you have to options, 75neither of which are easy. You can rewrite to use threads, or you can re-exec 76yourself with special flags to pass along updated runtime state. This is what 77the self_exec() helper function in LTP is designed for. 78 79------------------------- 80--- No overcommitting --- 81------------------------- 82 83Virtual memory allows people to do malloc(128MiB) and get back a buffer that 84big. But that buffer is only of virtual memory, not physical. On a NOMMU 85system, the memory comes immediately from physical memory and takes it away 86from anyone else. 87 88Avoid large mallocs. 89 90--------------------- 91--- Fragmentation --- 92--------------------- 93 94On a MMU system, when physical memory gets fragmented, things slow down. But 95they keep working. This is because every new process gets a clean virtual 96memory address space. While processes can fragment their own virtual address 97space, this usually takes quite a long time and a lot of effort, so generally 98it is not a problem people hit. 99 100On a NOMMU system, when physical memory gets fragmented, access to large 101contiguous blocks becomes unavailable which means requests fail. Even if your 102system has 40MiB _total_ free, the largest contiguous block might only be 1MiB 103which means that allocations larger than that will always fail. 104 105Break up your large memory allocations when possible. Generally speaking, 106single allocations under 2MiB aren't a problem. 107 108----------------- 109--- No paging --- 110----------------- 111 112No virtual memory means you can't mmap() a file and only have the pages read in 113(paged) on the fly. So if you use mmap() on a file, the kernel must allocate 114memory for it and read in all the contents immediately. 115 116--------------------- 117--- No swap space --- 118--------------------- 119 120See the "No paging" section above. For the same reason, there is no support 121for swap partitions. Plus, nommu typically means embedded which means flash 122based storage which means limited storage space and limited number of times 123you can write it. 124 125------------------------- 126--- No dynamic stacks --- 127------------------------- 128 129No virtual memory means that applications can't all have their stacks at the 130top of memory and allowed to grown "indefinitely" downwards. Stack space is 131fixed at process creation time (when it is first executed) and cannot grow. 132While the fixed size may be increased, it's best to avoid stack pressure in 133the first place. 134 135Avoid the alloca() function and use malloc()/free() instead. 136 137Avoid declaring large buffers on the stack. Some people like to do things 138such as: 139 char buf[PATH_MAX]; 140This will most likely smash the stack on nommu systems ! Use global variables 141(the bss), or use malloc()/free() type functions. 142 143------------------------------- 144--- No dynamic data segment --- 145------------------------------- 146 147No virtual memory means that mappings cannot arbitrarily be extended. Another 148process might have its own mapping right after yours! This is where the brk() 149and sbrk() functions come into play. These are most often used to dynamically 150increase the heap space via the C library, but a few people use these manually. 151 152Best if you simply avoid them, and if you're writing tests to exercise these 153functions specifically, make them nops/XFAIL for nommu systems. 154 155------------------------------- 156--- Limited shared mappings --- 157------------------------------- 158 159No virtual memory means files cannot be mmapped in and have writes to it 160written back out to disk on the fly. So you cannot use MAP_SHARED when 161mmapping a file. 162 163------------------------- 164--- No fixed mappings --- 165------------------------- 166 167The MAP_FIXED option to mmap() is not supported. It doesn't even really work 168all that well under MMU systems. 169 170Best if you simply avoid it, and if you're writing tests to exercise this 171option specifically, make them nops/XFAIL for nommu systems. 172