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