Memory ProtectionOne common complaint or feature request for RISC OS improvement is to add “memory protection”. This is largely a result of the relative ease of which single programs can take out the entire operating system, combined with a misunderstanding of what precisely memory protection is. In this article, Peter Naulls will try and cover some of the issues around memory protection, and why RISC OS is often so susceptible to breakage and some of the measures which can be taken to improve the situation.
that thing was a gift from chip makers or developers asked for it?
i mean if HW memory checking never was invented, software would be forced to use explicit memory bound checks
and
HW memory checks are done on every memory access, even if it’s not necessary… if those checks were done explicitly by the compiler, placed only where needed and nowhere else, at the end the result won’t be faster?
(excuse my english)
Memory protection has been pushed into hardware precisely because it can’t be done nearly as fast in software. If it was only done in software, you’d need to look something up every single time you accessed memory. This would require loading a small amount of code for each and every memory read or write done, combined with having a detailed list of what is “valid” memory to read or write, and only going within those bounds. The problem with this is that a misbehaving application with bugs can still trounce that memory that is in the valid range, say, rewriting the code that verifies the correct bounds, and still completely defeating the purpose of attempting to provide memory bounds checking purely in software.
The software solution that wouldn’t work like described above would slow down the code horribly: you might as well go to not having any memory protection at all, and very carefully write and test software, but then it’d not be likely to get completed in a useful timeframe.
By comparison, by using hardware, the extra chip registers that track all that happen to compute whether or not memory accesses are correct at exactly the same time as all the other computations are done, without adding to program complexity. Since the page registers only need to be loaded from the page tables in memory on the (in well-written software) rare basis that another page is accessed (or attempted at being accessed) that’s not already in the Translation Lookaside Buffer table on chip (on x86 the default page size is 4K, but it can be larger) the actual hardware overhead is relatively low when spread across many memory accesses in the application.
While it still doesn’t protect the process from reading or writing data out of bounds of what’s intended for the data area of that process (ie. you can read or write from some variable you didn’t intend to due to a bug) it won’t allow you to touch the address space of another process, and all with a very small amount of overhead.
Now, there is quite a bit of overhead in comparison when the page isn’t in memory and you try to access it, but there’s no way that can be made any faster by doing it entirely in software than how it’s handled now: by triggering a special type of interrupt that’s handled by the OS, which presumably knows enough about what’s going on to swap memory out in a productive manner. It isn’t impossible for the paging out to a disk to be done entirely in hardware, but it likely wouldn’t be much faster, and it would tie the processor to storage devices too much.
So, while hardware paging and memory protection has its overhead that slows things down a little bit (no pun intended!) it’s still faster than trying to do all the memory protection entirely in software, unless you ensure that the applications that are run are perfectly behaved and never stray outside their memory space. While that can be done, it doesn’t happen 100% of the time, unfortunately .
“If it was only done in software, you’d need to look something up every single time you accessed memory.”
i’m talking about language based memory protection: you don’t need to check every single time you access a memory, only every time you goin to touch first time a block of memory. if the program access only his variables (there’s no pointers, like python, lisp), you can trust that never going to touch anything else, and there’s no need to check. If you make a loop to use an array, previous to enter the loop you make checks to not going outside bound, and then you proceed without worries. The problem i see is paging and virtual memory, but if compiler can foresee pages, can align variables in one page and check page fault in a row, you don’t need to check page fault for every byte, only for every block of memory (although this needs that the compiler put declarations about pages to be used and released inside the code, and when a program is suspended by task switch, a list of working pages need to be stored too, so prevously to come back to work again, his working pages are restored in memory). Finally you can gain some speed because program share one big adresspace and there less overhead in process intercomunication.
With this, chips can be more simple, and this, i hope, makes room for more speed.
the problems:
– actual chips forces memcheck and make all this slow (this is throwing all complexity to the compiler, will be needed a microcode compiler).
– need high level langs, and people have to trust in his efficency, always will be someone tempted to program in microcode by hand…
– programs installed in a system will have to be source based or vendors have to ship it compiled but with a thousand of oaths.
I say all this based on analisis of isolated processes, i don’t know how frecuent these occurs and maybe now by statistics the current way is more efficient, but always old ideas come back.
lol!
You’ve put WAAAAAAAYYYYY too much faith in compiler and VM writer’s ability to create perfect tools
There’s also the fact that many of those scripting languages heavily use libraries written in other “unsafe” languages such as C/C++. Python would be too slow if everything were interpreted. And think about this: what is the python interpreter written in?
I’ve seen too many internal compiler errors crashing the compiler to have faith that the code that’s generated will work as written 100% of the time. There are many cases you can show that properly written source code that works fine on one compiler and is 100% valid according to the language standard is incorrectly optimized, and sometimes incorrectly compiled when not optimized.
I’ll give you an example: the Borland C++ compiler (not sure exactly which small release) had a bug with the “,” operator generating correct code in certain situations, around version 5.0 which caused in certain types of builds for things to build incorrectly. No compiler/linker warnings were generated: the code simply didn’t work correctly when built. The code that used this was involved in some fancy debugger macros, so I’d like to think most people wouldn’t write code this way.
How many times have you seen the Java VM crash? I’ve seen it crash more than once.
It’s one thing to have one application written perfectly so memory protection isn’t required, but completely unrealistic to expect everything to be written perfectly. It only takes one application that steps outside its memory bounds to randomly corrupt any and all other applications in a system that doesn’t have hardware memory protection. Hopefully, the one application that is perfect for memory accesses is the OS that runs in kernel space, because it would be a problem making it totally isolated.
As hardware page protection is currently implemented in most VM supporting chips I’m aware of, there’s only a couple of memory access overheads once you’ve left the bounds of the set of pages that have cached MMU registers on the CPU. Unless the software is written with very poor locality of reference where it is touching a different page of memory with every access, there’s a very small fraction of 1% performance hit to verify that the program doesn’t exceed its bounds, until you have a VM page miss, which can’t be sped up by a pure software method anyway without adding a huge amount of system/application code overhead.
VM and page protection have no value on a system that only has one process executing at a time: it’s something that allows more than one process running to not be unduly affected by everything else should there be a problem, and to allow processes to act as though there’s more memory than there actually is. Having VM and page protection in hardware, while it has a small overhead, has a much higher overall performance boost to the system, partially because only the OS itself needs to deal with there not being enough RAM to make everyone happy. The OS can optimize performance on the system level much better than any application can deal with things.
What you have said works perfectly fine in an embedded system with carefully written and tested code created by a single entity, and such systems don’t usually require an OS.