Page 1 of 1

Is the kernel the first task executed by the system ?

Posted: Sun Apr 11, 2021 1:35 pm
by bobgimax
Hi everyone,

I'm new to in the osdev world and I decided to first write a simple bootloader as a warm-up before diving in the kernel stuff.
I understood that the bootloader must switch the CPU to protected prior to jumping to the kernel code so I read Intel Software Developer's Manual and in Volume 3, section 9.9.1 Switching to Protected Mode and it's said that after switching to protected mode the system must execute a task (even if the system won't use hardware multitasking). That implies setting up a TSS etc before switching to PM.
I conclude that the kernel must be the first task executed by the system and that this must be done a few instructions after switching to PM.

The wiki pages about bootloaders don't tell much about this so I'm wondering if a bootloader must really execute the kernel as the first task of the system ? Or is it the job of some sort of "kernel first stage" ?

Thank you

Re: Is the kernel the first task executed by the system ?

Posted: Sun Apr 11, 2021 2:22 pm
by rdos
I don't think you need to load the TR register until you run your first usermode code, provided you don't use hardware task-switching. This is because the TSS contains the kernel mode stack.

Re: Is the kernel the first task executed by the system ?

Posted: Sun Apr 11, 2021 2:50 pm
by kzinti
rdos wrote:I don't think you need to load the TR register until you run your first usermode code, provided you don't use hardware task-switching. This is because the TSS contains the kernel mode stack.
This is correct. You don't need to setup a TSS to get your kernel started.
bobgimax wrote:I conclude that the kernel must be the first task executed by the system and that this must be done a few instructions after switching to PM.
When your bootloader jumps to the kernel code, the kernel starts executing. At this point, you haven't initialized the scheduler or the task management system yet. So there is no "task" to talk about just yet.

When and if the initial execution flow in your kernel becomes a task is up to you. You get to decide what constitutes a task or not.

In my kernel, I convert the initial execution flow into Task 0 after I am done initializing basic systems like physical and virtual memory management, CPU related structures, CPU exceptions and interrupts and so on. I do this when initializing the scheduler. But you don't have to do it this way. You could just decide to allocate your first task dynamically and "switch" to it, letting the initial execution flow die.

Re: Is the kernel the first task executed by the system ?

Posted: Sun Apr 11, 2021 10:27 pm
by nullplan
bobgimax wrote:I understood that the bootloader must switch the CPU to protected prior to jumping to the kernel code so I read Intel Software Developer's Manual and in Volume 3, section 9.9.1 Switching to Protected Mode and it's said that after switching to protected mode the system must execute a task (even if the system won't use hardware multitasking). That implies setting up a TSS etc before switching to PM.
I conclude that the kernel must be the first task executed by the system and that this must be done a few instructions after switching to PM.
I think there is a mistake in your modelling: The kernel is not just one task. Indeed it could be argued that all tasks are kernel tasks, just some spend the majority of their time executing user space programs.

The CPU will be satisfied with a valid value in the Task Register, and even that will only be necessary once multiple privilege levels get involved. It is completely proper for the bootloader not to set up a TSS and leave that to the kernel. Common sequence is that:
  1. Bootloader uses BIOS Interrupts to load kernel et. al. into memory.
  2. Bootloader loads GDT.
  3. Bootloader switches to protected mode and jumps to kernel
  4. Kernel sets up paging.
  5. Kernel loads another GDT/IDT, now that the addresses are fixed
  6. Kernel loads the Task Register with a Task Gate.
Admittedly, the paging set up might also be done by the bootloader. It depends on the protocol. In my case, I have a 64-bit OS, so it is a bit more complicated. But having to load a new GDT in the kernel is nothing out of the ordinary, and only once the final GDT has been loaded does it make sense to load the Task Register.

Notice that the CPU has absolutely no interest in the task organization you have going on in your OS, especially if you don't use hardware task switching. I will build my OS such that the first task, which automatically gets PID 0, will end up being the idle task, and the second task, getting PID 1, will be the init task. PID 1 is special and reserved by POSIX, so I have to do it like this. But after that, anything goes.

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 1:06 am
by rdos
kzinti wrote: In my kernel, I convert the initial execution flow into Task 0 after I am done initializing basic systems like physical and virtual memory management, CPU related structures, CPU exceptions and interrupts and so on. I do this when initializing the scheduler. But you don't have to do it this way. You could just decide to allocate your first task dynamically and "switch" to it, letting the initial execution flow die.
There is one complication that might make you want to load the TR register earlier. If you handle some exceptions with tasks, for instance, double fault, then you need to have TR loaded for that to work otherwise double fault will turn into triple fault. So, in my design, I load a dummy task during kernel initialization so I correctly can catch double faults.

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 1:10 am
by rdos
nullplan wrote:Admittedly, the paging set up might also be done by the bootloader. It depends on the protocol. In my case, I have a 64-bit OS, so it is a bit more complicated. But having to load a new GDT in the kernel is nothing out of the ordinary, and only once the final GDT has been loaded does it make sense to load the Task Register.
I have a per core GDT. I use it so I can load a fixed selector (which is mapped differently for each core) to quickly get the current core control block segment.
nullplan wrote:Notice that the CPU has absolutely no interest in the task organization you have going on in your OS, especially if you don't use hardware task switching. I will build my OS such that the first task, which automatically gets PID 0, will end up being the idle task, and the second task, getting PID 1, will be the init task. PID 1 is special and reserved by POSIX, so I have to do it like this. But after that, anything goes.
Apart from the pseudo-task to be able to cope with task-based exceptions, the first real task in my system is the idle task for the BSP. Since I have a pseudo-task, I can just put it in the ready queue and let the scheduler switch to it just like a normal task switch.

I have a task segment per thread even if I don't use hardware task switching anymore. I still save the register state in this area too which makes it easier to inspect the register state of debugged threads.

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 6:43 am
by bzt
bobgimax wrote:I conclude that the kernel must be the first task executed by the system and that this must be done a few instructions after switching to PM.
That depends how you define "task". When you power on the machine,
  • first the firmware runs. You could consider this a task (but usually it isn't). It initializes the hardware and loads the bootloader.
  • then bootloader runs, which is the first code loaded from disk, so you could consider this a task too. The bootloader loads the kernel and other parts of the operating system.
  • then the bootloader passes control to the kernel. You could say kernel init is a task too, but usually it isn't called like that. The kernel initializes, sets up environment for user space tasks.
  • when the kernel finished with the initialization, it performs the first task switch to drop privileges and starts running a user space task
  • in UNIX, that first user space task is the "/sbin/init", with pid 1, and because that's the first thing that runs after an actual task switch, it is considered to be the first real task
Of course this is just a vague description, the bootloader could be part of the firmware for example, and kernel might create multiple threads (starting kernel threads in the Linux kernel is a relatively recent addition, early versions did not do that). You could also call a kernel thread a task, this is only a matter of interpretation. OS that uses only kernel space also exists. In most common sense, the first task is the code (either user or kernel mode) that runs after the very first actual task switch (which also could be a software-only implementation, not using TR and TSS to separate tasks at all).
bobgimax wrote:The wiki pages about bootloaders don't tell much about this so I'm wondering if a bootloader must really execute the kernel as the first task of the system ? Or is it the job of some sort of "kernel first stage" ?
Depends entirely on how you design your kernel. The kernel's entry point could be a trampoline code (a "kernel first stage" in your parlance), but not necessary, a bootloader can set up everything for the kernel as well (for example with GRUB, there's no need for a PM switch, GRUB does that for your kernel).

Cheers,
bzt

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 10:22 am
by bobgimax
Hi,

Thank you very much for all your answers !!
When I said "task" I was indeed referring the definition of a task in Chapter 7 of the Intel Developer's Manual : A unit of work that the processor can dispatch using task management facilities such as the TR register, TSSs etc. Anyway, if I understand you all, there's nothing wrong with jumping to the kernel code in protected mode with a "raw" far jump, not using any of the task management facilities provided by the CPU.
It seems to me now that it's much simpler to start the first task after the kernel loaded a new GDT/IDT, maybe paging etc.

Feel free to correct me if I missed something otherwise I'll close the thread. Thanks again

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 1:37 pm
by sj95126
bobgimax wrote:Anyway, if I understand you all, there's nothing wrong with jumping to the kernel code in protected mode with a "raw" far jump, not using any of the task management facilities provided by the CPU.
Yes, that's basically it, though you don't need a "far" jump in the sense of an "inter-segment" jump. If you're already in protected mode, and CS already refers to the code segment you want to use, an absolute near jump is all you need. Either place the address of the kernel entry in a register and perform a register-indirect jump, or push the address on the stack and "ret". (the latter is how I jumped to the kernel when my OS was 32-bit).

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 3:48 pm
by bzt
bobgimax wrote:When I said "task" I was indeed referring the definition of a task in Chapter 7 of the Intel Developer's Manual : A unit of work that the processor can dispatch using task management facilities such as the TR register, TSSs etc.
Ah, yes. To differentiate that's usually referred to as "hardware task switch". No mainstream OS kernels use that feature.
bobgimax wrote:Anyway, if I understand you all, there's nothing wrong with jumping to the kernel code in protected mode with a "raw" far jump, not using any of the task management facilities provided by the CPU.
Yes, usually referred to as "software task switch". This is what most OS (mainstream and hobby alike) do. They keep one instance of TSS only (because of the kernel stack pointer), but instead of chaning TR they just replace values in the segment if/when needed. If you don't change CR3 on software task switch, then all your tasks will use the same address space (insanely fast but unsecure, called software isolated processes, very uncommon). If you change CR3 too on a task switch, then each process will have it's own address space (slower because it flushes the TLB on task switch, but secure, common practice).

Cheers,
bzt

Re: Is the kernel the first task executed by the system ?

Posted: Mon Apr 12, 2021 10:54 pm
by linguofreak
bobgimax wrote:Hi,

Thank you very much for all your answers !!
When I said "task" I was indeed referring the definition of a task in Chapter 7 of the Intel Developer's Manual : A unit of work that the processor can dispatch using task management facilities such as the TR register, TSSs etc. Anyway, if I understand you all, there's nothing wrong with jumping to the kernel code in protected mode with a "raw" far jump, not using any of the task management facilities provided by the CPU.
The kernel is not a task, because it defines what a task *is*. The TSS mechanism was an attempt by Intel to provide hardware infrastructure that kernels could use to speed up task switching, but they bit off more than they could chew and it ended up being slower and more awkward than having the kernel manage tasks entirely on its own.

Re: Is the kernel the first task executed by the system ?

Posted: Tue Apr 13, 2021 12:49 am
by rdos
bzt wrote:Yes, usually referred to as "software task switch". This is what most OS (mainstream and hobby alike) do. They keep one instance of TSS only (because of the kernel stack pointer), but instead of chaning TR they just replace values in the segment if/when needed. If you don't change CR3 on software task switch, then all your tasks will use the same address space (insanely fast but unsecure, called software isolated processes, very uncommon). If you change CR3 too on a task switch, then each process will have it's own address space (slower because it flushes the TLB on task switch, but secure, common practice).
Just because you use software task switching doesn't mean the TR is useless. Apart from having the per-task kernel stack, it also has the IO permission bitmap. It's also possible to save the TR register at user level with str, allowing for a fast thread ID that doesn't require syscalls or fixed usage of fs or gs, which only apply to C code anyway. And the register area of the TSS is needed anyway to save the register context of the task.

Re: Is the kernel the first task executed by the system ?

Posted: Tue Apr 13, 2021 11:49 am
by Octocontrabass
rdos wrote:It's also possible to save the TR register at user level with str, allowing for a fast thread ID that doesn't require syscalls or fixed usage of fs or gs, which only apply to C code anyway.
But then your GDT needs to hold enough entries so each thread can get its own ID, and you need to change TR on each context switch. If you have one TSS per address space, you don't need to change TR at all: just map different pages for the TSS. (For SMP, you need one TSS for each CPU in each address space.)

Keep in mind that if your usage of FS/GS doesn't follow the C ABI, it will be harder to patch compilers to target your OS, even for languages that are not C.
rdos wrote:And the register area of the TSS is needed anyway to save the register context of the task.
When you're not using hardware task switches, you can save the register context somewhere else.

Re: Is the kernel the first task executed by the system ?

Posted: Tue Apr 13, 2021 1:28 pm
by rdos
Octocontrabass wrote: But then your GDT needs to hold enough entries so each thread can get its own ID, and you need to change TR on each context switch. If you have one TSS per address space, you don't need to change TR at all: just map different pages for the TSS. (For SMP, you need one TSS for each CPU in each address space.)
Every thread actually uses two GDT entries. One for the TSS and one for the thread control block. Since GDT can have 8191 entries, this is not really a problem since typical setups at most have less than 100 threads.

Actually, in the normal setup, the kernel stack will use an additional GDT entry, although it's also possible to use a flat stack, but I only use that option when I have too (when I run under long mode).
Octocontrabass wrote: Keep in mind that if your usage of FS/GS doesn't follow the C ABI, it will be harder to patch compilers to target your OS, even for languages that are not C.
I use the LDT for FS (TLS). There is no reason why TLS would use GDT entries. The ltr trick is only useful for assembly-code or environments where the ABI doesn't have a TLS area.