The problem in monolithic operating systems is that each module sees all other modules all the time. Microkernels solve this problem by completely isolating one module from the other, and using special mechanisms for communication between modules. But microkernels have their own complexity and set of well-known problems.
So how about doing a flat-address 'monolithic' kernel where each module is isolated from the others? on 80x86, it could be done by a trick: manually changing the base and offset of the CS segment descriptor on an inter-module call.
A good question is why to change the contents of the CS segment descriptor manually when a far jump can do it automatically. Well, for the following reasons:
1) the LDT has not that many entries (perhaps 16K modules are not enough).
2) the CPU's caches are better utilized if the LDT is short.
3) the protection check is avoided.
When changing the CS segment descriptor manually, a problem may come up: the new CS:IP address might be invalid! so in order to avoid this problem, invocation of the inter-module procedure should be performed through another procedure which has the same IP address in both modules!
The pseudo-assembly for the inter-module invocation could be like this:
Code: Select all
SWITCH_MODULE:
mov EAX, <target address> ;load target address, relative to the target module
mov ECS:EDX, <current CS descriptor> ;load current CS descriptor in 64-bit register
mov [<address of CS descriptor>], <target CS descriptor> ;change the CS descriptor
NO_MANS_LAND:
NOP
NOP
...
NOP
RETURN_POINT:
Code: Select all
INVOKE_TARGET:
call EAX ;call the target subroutine which saves ECX and EDX
mov [<address of CS descriptor>], ECS:EDX ;return to caller
END_INVOKE_TARGET:
The benefits of this trick are:
1) the target module can't randomly invoke other modules. Any access outside the module will result in an exception.
2) the TLB is not flushed (not like when changing CR3).
3) there is no need for a full context switch.
All that it takes for this to work is to invoke the target procedure through another procedure which has a common address between the two modules.
The rest of the registers can be modified accordingly (including the data and stack segments).
What do you think? I would like your advice if it could work.