jpdoane wrote:
Should I be differentiating between the small kernel stacks I need to set up for system calls and ISRs, vs the primary stack for persistent kernel-mode processes (e.g. scheduler, drivers, etc).
Yes, I'd give the system call and interrupts their own stack. The scheduler, for example, triggers with a timer interrupt and would use your ISR stack. For most cases the ISRs should be short (e.g. they wake up a driver.) Even a heavy system call (e.g. if you had a system call that was "download Assassin's Creed Valhalla" which would take a while to download 50 GB) doesn't have to do all the work in the system call handler. You could either create a thread or wake up a thread that does the actual download, put the calling thread to sleep, then return from the handler into the next awake thread. No need to do any heavy work in the system call handler itself, even if by putting the calling thread to sleep while the work is being done gives the illusion to the process that it's a long running system call.
For other things the kernel may do (e.g. drivers in a monolithic kernel), unless you're planning on having a single threaded kernel that uses an event loop, there wouldn't be a "primary" kernel thread/stack. You'd have one stack per thread, and each driver/service can create as many threads as they want, and each thread would have their own stack.
A kernel's main() function usually ends along the lines of:
Code:
asm("sti");
for(;;) asm("hlt");
You enable interrupts (which kicks your scheduler into gear and transfers control to a running thread), and the "primary" thread is kept around as the "idle thread" you switch to when your schedule can't find any other awake threads.