Page 123 - DCAP103_Principle of operating system
P. 123

Principles of Operating Systems



                   Notes         4.4.2 Memory Protection
                                 Fault tolerance begins with memory protection. For many years, microprocessors have included
                                 on-chip memory management units (MMU) that enable individual threads of software to run
                                 in hardware-protected address spaces. But many commercial real-time operating systems never
                                 enable the MMU, even if such hardware is present in the system.
                                 When all of an application’s threads share the same memory space, any thread could-intentionally
                                 or unintentionally-corrupt the code, data, or stack of another thread. A misbehaved thread could
                                 even corrupt the kernel’s own code or internal data structures. It is easy to see how a single
                                 errant pointer in one thread could easily bring down the entire system, or at least cause it to
                                 behave unexpectedly.
                                 For safety and reliability, a process-based real-time operating system (RTOS) is preferable. To
                                 create processes with individual address spaces, the RTOS need only create some RAM-based
                                 data structures and enable the MMU to enforce the protections described therein. The basic idea
                                 is that a new set of logical addresses is “switched in” at each context switch. The MMU maps a
                                 logical address used during an instruction fetch or a data read or write to a physical address in
                                 memory through the current mapping. It also flags attempts to access illegal logical addresses,
                                 which have not been “mapped” to any physical address.

                                 The cost of processes is the overhead inherent in memory access through a look-up table. But
                                 the payoff is huge. Careless or malicious corruption across process boundaries is rendered
                                 impossible. A bug in a user interface thread cannot corrupt the code or data of a more critical
                                 thread. It’s truly a wonder that non-memory protected operating systems are still used in complex
                                 embedded systems where reliability, safety, or security are important.
                                 Enabling  the  MMU  has  other  benefits  as  well.  One  big  advantage  stems  from  the  ability  to
                                 selectively map and unmap pages into a logical address space. Physical memory pages are
                                 mapped into the logical space to hold the current process’ code; others are mapped for data.
                                 Likewise, physical memory pages are mapped in to hold the stacks of threads that are part
                                 of the process. An RTOS can easily provide the ability to leave a page’s worth of the logical
                                 addresses after each thread’s stack unmapped. That way, if any thread overflows its assigned
                                 stack,  a  hardware  memory  protection  fault  will  occur.  The  kernel  will  suspend  the  thread
                                 instead of allowing it to corrupt other important memory areas within the address space (like
                                 another thread’s stack). This adds a level of protection between threads, even within the same
                                 address space.

                                 Memory  protection,  including  this  kind  of  stack  overflow  detection,  is  often  helpful  during
                                 the development of an application. Programming errors will generate exceptions that are
                                 immediately detected and easily traceable to the source code. Without memory protection, bugs
                                 can cause subtle corruptions that are very difficult to track down. In fact, since RAM is often
                                 located at physical address zero in a flat memory model, even NULL pointer dereferences will
                                 go undetected! (Clearly, logical page zero is a good one to add to the “unmap list.”). Another
                                 issue is that the kernel must protect itself against improper system calls.


                                                The kernel must protect itself against improper system calls. Many kernels
                                                return the actual pointer to a newly created kernel object, such as a semaphore,
                                                to the thread that created it, as a handle. When that pointer is passed back
                                                to  the  kernel  in  subsequent  system  calls,  it  may  be  dereferenced  directly.
                                                But what if the thread uses that pointer to modify the kernel object directly,
                                                or simply overwrites its handle with a pointer to some other memory. The
                                                results may be disastrous.







        116                               LOVELY PROFESSIONAL UNIVERSITY
   118   119   120   121   122   123   124   125   126   127   128