I'm writing a small bootloader for an x86 based PC. The problem is that the CPU is somehow still active after executing these instructions:
sti
hlt
sti is supposed to disable interrupts for the next instruction
hlt is supposed to completely halt the processor
Since they're used together, I assumed they would just 'freeze' the computer. But when I assemble it and mount it in VirtualBox as a floppy image, my CPU jumps to 100%.
What am I doing wrong?
I would like to add a comment about 'cli' as I have been bitten by this a couple of times in the past. The 'cli' instruction does not block all interrupts--it only blocks the maskable ones. Conceivably, the system could still be woken up due to a non-maskable interrupt (NMI).
As one of the comments indicates that the computer is ready to be turned off, I expect that there are no other threads/processes/tasks ready to run in the system (otherwise an NMI could conceivably lead to a reschedule). For the scenario you describe an NMI is unlikely; however depending upon your level of paranoia of things going wrong, you may wish to add a loop to guard against the possibility.
sysSuspend:
cli
hlt
jmp sysSuspend
I think you are a bit confused about both of these commands.
The sti
command enables interrupts and the cli
command disables them.
The halt state is similar to an idle loop, so it doesn't suspend the processor.
Here are some links that may help you: Info on the STI/CLI commands: http://en.wikipedia.org/wiki/STI_%28x86_instruction%29
Info on the x86 instructions: http://en.wikipedia.org/wiki/X86_instruction_listings
From here there is a link to the hlt
command that may help.
If you suspend the processor, how do you wake it up again, if you disable the interrupts?
This question can be reformulated into more correct question: how to completly suspend the control flow? In fact this task can be split into two subtasks:
Suspending of the current (synchronous) control flow.
Simple busy loop (100% CPU usage, big power consumption, high thermal effect).
Halt based loop (power saving mode C1, most of CPU logic unpowered).
Prevention of the asynchronous switching of control flows.
Stub interrupt handlers in IDT.
Masking of the interrupts on global interrupt controller (PIC or IO APIC).
Masking of the interrupts on local interrupt controller (Local APIC).
Masking of the interrupt on CPU core logic.
In any case, you must be aware and be prepared to NMI handling, because there is no mechanisms which give you power to disable them.
Ideal solution:
mov EDX, NMI_INT_HANDLER_STUB; // address of installed handler
mov ECX, 0x02 ; // id of the NMI handler in IDT
call InstallHandlerInIDT ;
cli ; // mask all maskable interrupts on CPU core
SUSPEND:
hlt ; // turn CPU into HALT state (power saving mode C1)
jmp SUSPEND ; // try again if NMI had happened
NMI_INT_HANDLER_STUB:
iretd ; // Complete handling immediatelly and return back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With