Hi,
AJ wrote:I have got the hang of stack-based multitasking and hardware task switching now, and have a 'sub version' of my kernel which uses each type.
Excellent! - any chance of some perfomance statistics to compare each method?
AJ wrote:Just one question - how does everyone tackle privilege-level switching? Do you generally just have one kernel tss, one user tss and load the details in to each one as required?
No - you have a single static TSS for everything, and (if necessary) dynamically change the SS0:ESP0, SS1:ESP1 and/or SS2:ESP2 fields during each (software) task switch.
For most OS's SS0 never needs to be changed, and SS1:ESP1 and SS2:ESP2 aren't used. If your kernel uses a single kernel stack (for all tasks) then you don't need to change ESP0 either.
In addition, if you use the I/O permission bitmap you'd want to change that during the task switch. Having a flag to indicate when this bitmap contains "no I/O access" can speed things up (as most tasks wouldn't have access to any I/O ports).
AJ wrote:Also, if I wanted to restrict port access from userland code, presumably I would have to do the same thing - set up one tss with the appropriate port bitmap, and then change this bitmap for each user program I want to restrict.
There are alternative methods - for example, you can restrict I/O port access using the general protection fault handler (i.e. user mode code always generates a GPF, and the GPF handler checks if the access should be allowed and emulates the I/O port access). This can save messing about with the TSS during task switches. It is slower, but I/O port access is slow anyway. Another way is to have kernel functions for I/O port access.
Which method is best depends on a lot of things (mostly, how often user-code accesses I/O ports, how much time it takes to fill the I/O permission bitmap when necessary, and how much time a kernel API call and/or general protection fault take). IMHO this means if you're doing task switches very frequently, the overhead of using the I/O permission bitmap will be more than the overhead of the kernel API and/or general protection fault handler.
You could also probably use several methods - for example, don't start using the I/O permission bitmap for a task until the task accesses several I/O ports (and occasionally stop using the I/O permission bitmap). That way, for something like a keyboard device driver you'd avoid the I/O permission bitmap for normal IRQs (where it only reads from one I/O port between task switches).
Cheers,
Brendan