|
(Most) drivers are supposed to run in ring 1 or 2 - call that "driver mode" if you like.
I guess that the OS kernel has some central drivers of its own running in ring 0. The borderline is fuzzy between drivers and code for manipulating CPU resources (such as the interrupt system or MMS). The OS may trust itself. It should not trust "foreign" drivers, e.g. those developed by manufacturers/vendors of "foreign" peripherals, to run in ring 0.
|
|
|
|
|
What (admittedly little) exposure I've had to this had led me to conclude that, for all practical purposes, there was no such thing as Ring 1 and Ring 2, at least when it comes to Windows. I think Mark Russinovich even said so himself, but don't quote me on that.
Although it does make sense that this is where drivers ought to live.
|
|
|
|
|
The hardware offering certainly is there. A specific OS is not obliged to make use of it.
The 386 segment system looks like it was hand crafted to Windows of the day. But MS made attempts to make Window the universal OS for all sorts of processors (such as MIPS, Alpha, PowerPC, Itanium, ...). Since they do not all provide the same hardware support, MS chose to limit themselves to the bare minimum available on all processors and do their own software simulation, identical for all of it. The same goes for the protection system: They ignored all advanced mechanisms. All users shall have the same offering; we cannot give x86/x64 users a protection mechanism unavailable to users on other platforms.
Of course they could have designed a hardware abstraction layer that modelled both segment and ring mechanisms that could very easily be mapped to Intel hardware, but required far more software emulation on other processors (giving them a competitive disadvantage). Maybe they would have done that, if they had known at that time how other processors would dwindle away anyway. They didn't. A major factor may be that they picked up OS experts from other architectures that didn't provide such things, major design architects simply unfamiliar with how such mechanisms are used, so they ignored them.
I am quite sure that at least you were right, that Windows ignored the intermediate privilege levels (along with the segment mechanisms). I thought that in order to make a more robust kernel, they started pushing external drivers down to ring 1 a while ago. I may very well be wrong. Maybe what I have read is unfounded speculations, and I found it such a natural thing to do that I took for granted that the change was carried through.
If the OS code is structured like a crow's nest it might be very difficult to realize, though. I have strong suspicions that the current state of the Windows implementation is not quite what you would use as a model system if you were teaching a university level course in well-designed OS implementation.
|
|
|
|
|
trønderen wrote: I thought that in order to make a more robust kernel, they started pushing external drivers down to ring 1 a while ago.
That could very well be the case, my knowledge on this topic is years old. And Microsoft has since been spending resources on trying to re-architect at least some parts of Windows in the name of security (to what degree of success, is a matter for another discussion)
trønderen wrote: I have strong suspicions that the current state of the Windows implementation is not quite what you would use as a model system if you were teaching a university level course in well-designed OS implementation.
How very true. Software that old, with so many layers that have been added over the years decades, cannot be optimally clean.
|
|
|
|
|
trønderen wrote: The OS may trust itself.
That's a mistake if that's the case. I thought Windows these days only established trust by signing every file in the Windows folder (where practical).
|
|
|
|
|
"Trust" in the sense "May allow its own components write access to data structures that noone else trusted to modify". If it didn't trust itself to set up segment/paging tables, interrupt handlers etc., nothing could ever work.
Signing is a different sort of trust.
|
|
|
|
|
trønderen wrote: Signing is a different sort of trust.
Fair enough.
|
|
|
|
|
k5054, dandy72, tronderen that’s an interesting read guys
|
|
|
|
|
"Intend your puns, weaklings" - Old Fire Emblem game.
Bond
Keep all things as simple as possible, but no simpler. -said someone, somewhere
|
|
|
|
|
Calin Negru wrote: Windows XP and it’s predecessors did pretty good at recovering when an application went kaboom
What do you mean?
Windows 3.1 would do a hard crash if the network went down.
Databases back then were always corrupting the actual data files due to hardware failures. Or even normal hardware operation. Forums were always filled with questions about how someone needed to attempt to recover their database files. This was true for all the databases I saw back then Oracle, SQL Server and MS Access.
Standard operating procedure in an editor was to manually save the file every couple of minutes, because if it crashed you lost everything. Editors at some point started adding a standard feature to automatically save the file because of that.
|
|
|
|
|
> Windows 3.1 would...
I’m not going to argue. When I said predecessors I had in mind mostly the later versions (Windows95 and Windows98). Things got gradually better, Windows XP was pretty good for an OS thought for single core processors. What I’m trying to say, and this is only an impression, I wasn’t around programming when people were running Windows 98 or XP on their PCs, is that if you were playing the role of a programmer and did not dispose things properly (leaving a mess behind in your app on exit) the OS would have been unforgiving. On Windows 10 if you leave a mess on exit the OS won’t say a thing no dialog boxes or messages telling you about corrupted memory, or that the app has exited with errors.
modified 8-Sep-23 15:26pm.
|
|
|
|
|
In Win95, I remember having caused system crash by this single line, in my code:
int *a = 0;
Not sure whether this problem was fixed in Win98.
It is precisely these kind of coding issues which got handled better in the Dotnet era.
modified 8-Sep-23 21:51pm.
|
|
|
|
|
Yeah, a tiny bit left or right from the prescription and doom looming.
|
|
|
|
|
Calin Negru wrote: and did not dispose things properly (leaving a mess behind in your app on exit) the OS would have been unforgiving
I don't remember anything like that.
For example pipes did not exist. So certainly no way to leave one of those around.
Files were closed when the app exited.
Memory was returned when the app exited.
Pretty sure sockets were closed when the app exited.
Not sure about UI 'handles' but I think they were returned too, probably because they were actually virtual and handled in memory (see above.)
Now all of that is true. Except it is possible to leave a named pipe hanging around but that is pretty much exactly the point (the programmer, not the OS, is responsible for the lifetime.)
Keep in mind of course that right now, because of the way sockets are defined, when the app exits the sockets are not immediately closed. The protocol must be respected. But now and then if you have an open client socket and either unplug (hardware) from the network, crash the computer or power off the computer then the socket is, by definition, still open.
Calin Negru wrote: On Windows 10 if you leave a mess on exit the OS won’t say a thing no dialog boxes or messages telling you about corrupted memory, or that the app has exited with errors.
As stated that is not possible.
Regardless of how the application exits the memory is returned to the OS. Even if you overwrite the application stack and/or code space the memory will still be returned.
With older OSes it was easier to write into spaces where one shouldn't. Which is not the same as saying it was easy. Nor is one absolutely precluded from doing it now.
|
|
|
|
|
Any machine with memory paging (on the PC side, that is from 386) keeps the OS pages in pages that does not appear in the user process paging tables. The user process has no way of pointing to the OS data structures.
Furthermore, even within a single address space, section may be marked as read-only or execute-only, so even if they are addressable by some process, it cannot overwrite them. Many paging systems (including the 386 and its followers) also has a "ring" system: A process belongs to one "ring" (privilege level), and pages or segments require a minimum ring protection level for any sort of access.
There are lots of very good protection mechanisms available in the hardware (and in the software). The problem is to make developers use the available mechanisms (and to use them the correct way).
|
|
|
|
|
trønderen wrote: There are lots of very good protection mechanisms available in the hardware (and in the software). The problem is to make developers use the available mechanisms (and to use them the correct way). That's... that's the right question[^]
M.D.V.
If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about?
Help me to understand what I'm saying, and I'll explain it better to you
Rating helpful answers is nice, but saying thanks can be even nicer.
|
|
|
|
|
64 bit versions of Windows don't share memory with the applications. There is a small "communications" buffer between the system and the applications, and this buffer is unique to each application. It's used for those system calls that require the application read from or write data to a system call, but this memory is actually in the application space. 32 bit Windows sometimes allowed applications to read/write directly in system space and the biggest culprits for this were heavy graphics (the 386 didn't have the power to avoid this) and anti-virus software. In fact, the AV folks went ballistic when Microsoft announced this change in Windows Vista because they knew they had been violating Microsoft's documentation on how to write Windows apps.
|
|
|
|
|
tronderen, obermd, interesting thanks for sharing.
|
|
|
|
|
Calin Negru wrote: Both 32 bit and 64 bit OS share the RAM with the app, the common dwelling means that the app can overwrite critical OS data If that were so then Windows PCs would be crashing in their millions. User apps have no way of overwriting OS data as they exist in separate address spaces, and the non-OS parts have very low privilege levels.
|
|
|
|
|
|
And yet we still sometimes get the BSOD due to driver / other issues.
|
|
|
|
|
Hard to protect the OS against ill behaved drivers without introducing a nasty performance hit. Drivers basically need to operate in kernel space.
Windows does have "user mode" drivers now, but not everything can be run that way. It would destroy your GPU performance, for example.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
Remember the ring protection. Drivers are not supposed to run in ring 0. The (hardware) ring protection is effective at all times; it is not turned on or activated. Making use of it does not affect performance.
Then comes the questions of placing the various OS data structures in the appropriate ring. I wouldn't be surprised if there are essential data structures in ring 1 (/2) that really should be located in ring 0. But then the OS code referencing it must be located in ring 0 as well. If the OS wasn't originally architected with a ring protection in mind, cleaning it up later may be a rather nasty job.
I've never been inside Windows source code, but my experiences, not the least with (but certainly not limited to) Windows Docker, seems to indicate that it "Everything is deeply intertwingled" (to quote Ted Nelson). Picking apart a crow's nest to put some of the stick in the "ring 0" pile, without breaking any of the other sticks, requires extreme care.
Then learning Zephyr, seeing how it is possible to divide OS functionality into clear cut, small pieces so that you load exactly what you need and nothing more, was a revelation to me. It is the diametrical opposite to Windows. Of course: Zephyr and Windows targets (almost) completely different problem domains. Yet I am quite sure that a general OS like Windows could be built with much more of the Zephyr modular philosophy.
|
|
|
|
|
Maybe I misunderstand how things are laid out but I do know a driver can do a kernel wait without switching between "user mode" and "kernel mode" under windows. I assumed kernel mode was equiv to ring 0 but it sounds like the truth is more complicated.
Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix
|
|
|
|
|
Well, in OS/2 you had the following levels:
Level 0: Kernel and (some) drivers
Level 1: Most drivers
Level 2: IOPL (In, Out instructions) for use programs
Level 3: User programs
I don't know much about the Windows kernel, but I assumed that it had a similar structure.
Freedom is the freedom to say that two plus two make four. If that is granted, all else follows.
-- 6079 Smith W.
|
|
|
|