Hi,
ggodw000 wrote:I am working on to develop minimal linux kernel design to incorporate and solidify my practice and handson on concepts ie. task-switching, scheduling. I had limitation because of the realmode 1mb issue and now working on pmode switch along with IDT setup so I can enter pmode with interrupts enabled.
I found from Intel manual, that intel hardware already supplies TSS (task state segment) along with its descriptor with TR register to do a similar thing. What I have been working on was using solely stack, all the task switching was done without ever using TSS. Intel manual says TSS is optional and software implementation is possible. I just wanted to confirm that this is possible in protected mode.
When the CPU switches from a lower privilege level (e.g. CPL=3) to a higher privilege level (e.g. CPL=0) it loads SS and ESP from the current TSS (e.g. the current TSS's SS0 and ESP0 fields) to ensure that the more privileged code has a safe stack to use. This means that you have to use a minimum of one TSS to use different privilege levels.
Most OSs use CPL=3 (user-space) and CPL=0 (kernel) and use a single TSS so that switching from CPL=3 to CPL=0 works; then use software task switching for everything (where, if the OS uses one kernel stack per task, the task switch code modifies the TSS's ESP0 field to suit the new task).
ggodw000 wrote:Secondly I have successfuly coded pmode enter and exit code with interrupts disabled only, but now will need to be tasked with entering pmode with interrupts enabled, which means will need to setup whole IDT correctly. If anyone has done this, I would appreciate the help and hints down the road! I am using Barry's Intel architecture and also Intel software developer's manual for this purpose.
I'm not sure what you mean, but for all the possible interpretations that make sense I've done it before.
To make some sense of (parts of) what I'm about to say; you need to understand some other things first:
- Most hardware is designed to do things in the background and send IRQs if/when the device needs attention. This means that (with appropriate software) the CPU/s can be doing useful work while the disk controllers read/write sectors while the USB controller transfers data to USB devices while the video card transfers data between RAM and display memory while the network card is sending/receiving packets. By allowing the hardware to do many things in parallel you're able to get acceptable performance (including things like pre-fetching data before its needed).
- The main problem with BIOS (and UEFI) is that they're only intended to get an OS up and running, and their services/functions/APIs are synchronous (they don't return until/unless an operation completes). They make it impossible for different pieces of hardware to be doing things in parallel (and therefore make it impossible to get acceptable performance). For this reason an OS should stop using BIOS/UEFI (eventually) and should provide its own device drivers. It makes no difference what sort of OS it is (e.g. even for a single-tasking OS that runs in real mode and doesn't support multi-CPU, where using BIOS functions is easy, the OS should provide device drivers that support asynchronous IO and don't cripple performance).
- Initially the BIOS "owns" all the hardware and (to prevent devices getting all confused and broken) while the BIOS owns all the hardware you have to make sure that the BIOS interrupt handlers are used when hardware wants attention and sends an IRQ.
What this means is that during boot you need a "point of no return" where the OS takes ownership of all the hardware and never uses BIOS after that. Before the "point of no return" you make sure that the BIOS IRQ handlers are used for all IRQs. After the
"point of no return" you make sure that the BIOS IRQ handlers are not used for any IRQ.
Now..
If you want code that leaves interrupts completely enabled everywhere while switching between real mode and protected mode; then it doesn't make sense because it's impossible to do it reliably (without the risk of an IRQ interrupting at the worst possible time and interrupt handlers ending up in an unexpected "half real mode and half protected mode" state and crashing).
If you want code that leaves interrupts enabled in the CPU while switching between real mode and protected mode; then you can do this safely by masking all IRQ sources in the interrupt controller/s (e.g. PIC chips) beforehand, then switching CPU modes, then unmasking IRQs in the interrupt controller later. I consider this "best practice" when you're switching from real mode to protected mode for the last time (and only for the last time - e.g. only for that "point of no return"), because it avoids problems caused by stale interrupts intended for BIOS being received after you've stopped using BIOS. For all other cases it doesn't make sense (it's better to disable interrupts in the CPU instead of messing with the interrupt controller/s).
If you want code that disables IRQs while switching between real mode and protected mode; but then enables IRQs immediately after switching CPU modes (so that interrupts are enabled in protected mode) then that's potentially fine too; but depends on what you're doing and how you're doing it. If it's for that "point on no return" (where the OS is taking ownership of hardware) you can't install all device drivers instantly; which means that you want to mask all IRQs and enable them one at a time while the device's driver is initialised; and this is already mentioned above. If it's before the "point of no return" then you have to make sure the BIOS IRQ handlers are called (even when you're in protected mode when the IRQ is received), and this can be done in multiple ways:
- By having protected mode interrupt handlers that switch back to real mode and call the BIOS interrupt handlers (then switch back to protected mode after the BIOS has handled the IRQ). An example of this can be found here
- By using virtual8086 mode to execute the BIOS IRQ handlers
- By using emulation to execute/interpret the BIOS IRQ handlers
ggodw000 wrote:Lastly, I had some issues entering pmode currently (I am actually starting this project from scratch after abandoning and losing the previous attempt along with its source code). The target machine that entering pmode is a HYper-v virtual machine that is running on WS2012 R2 server and it is booting from virtual FDD to DOS. The exec file is launched that will go into protected mode. However machine is resetting which means something is wrong. I can put more details regarding my setup and code in my subsequent post in my thread.
While it's possible to boot from DOS, it means that before you reach the "point of no return" (before OS takes ownership of hardware) you don't just have to keep BIOS happy you also have to keep DOS happy. This includes not touching any memory that any part of DOS might be using; which (with the potential existence of extended memory managers) is all memory that you haven't explicitly allocated using DOS and/or its memory manager. Mostly, while it is possible, it's painful and far easier to boot from BIOS alone.
Cheers,
Brendan