devc1 wrote:I didn't understand what they add to an operating system, because you can just make drivers to manage I/O, File system, add features and subsystems ?
Imagine two ends of a spectrum:
On one side: The most monolithic kernel, where all code (drivers and all) live in the kernel.
On the other side: The most microkernel kernel, where the kernel is very small and just about every OS functionality is implemented in many small services and drivers that run as user programs.
But it's a spectrum, so if your question is "can I build an OS where all code lives in the kernel, except for drivers?" Yes. That would fall somewhere in the middle of the spectrum.
Maybe your question is "if you can implement all logic in drivers, what is the purpose of the OS having any logic outside of drivers?"
You could build an OS that way. But, it's useful for the OS (be it in the kernel or in a service that is not the driver) to share common code and ration resources. Imagine if you had a USB driver (for flash drives) and an ATA driver (for hard drives and disc drives) and your program wants to open a file by a path. Your program could ask each driver "can I open /home/andrew/documents/tax return.pdf?" and each driver would have to:
- Know where it's mounted.
- Know how all of the file systems that could appear on these devices (ExFAT, NTFS, ext3, etc.) work.
- Knows how to resolve symlinks and permissons, which could point to locations on other devices.
- Keep up with if multiple people are trying to write to the same file.
- On top of the above, know how to talk to the device to read and write data.
Or, you could have some common code (in the kernel for monolithic systems or a service for microkernels) that:
- Knows at what path all storage devices are mounted.
- Knows how to read different file systems (ExFAT, NTFS, ext3, etc..)
- Knows how to resolve symlinks and permissions.
- Keep up with if multiple people are trying to write to the same file.
Then all your USB and ATA storage drivers have to do:
- Report how big the device is.
- Know how to read and write to the device.
So, by having the common code (in the kernel or in a service) outside of the driver, the driver just has to worry about one specific thing (provide a common way to interact with this device regardless of make or model) and it makes your code more modular and easier to understand, because each service/driver just has to worry about its own job and not try to do everything.
Another example would be if the window manager (the code that draws where windows are, the title bar, handles resizing them, etc.) was implemented in the graphics card driver, and then upgrading the graphics card would completely change the look and feel of your OS. Then let's say you add a new feature your OS (such as you can theme your windows), some drivers would support theming, others may never get updated. Instead, if the graphics driver just worried about:
- Get and set the current resolution.
- Copy pixels onto the screen.
..you could implement the code that draws the windows, the title bar, handles resizing them, etc. into its own service. Then your OS would look and feel the same regardless of which graphics driver was being used, and it would be a lot less work for the developers of the driver.
Services in microkernels (or common kernel code in monolithic kernels) are useful and simplify things, because you put your common logic that should be shared or has to manage rationing resources into the services. Then you only have to implement the window drawing and dragging logic, the symlink resolving logic, the NTFS reading code, etc. once. Then your drivers become easier to build because they only have to worry the specifics of interacting with the hardware.