Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to completely suspend the processor?

Tags:

x86

assembly

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?

like image 392
Nathan Osman Avatar asked Sep 19 '10 23:09

Nathan Osman


3 Answers

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
like image 198
Sparky Avatar answered Oct 18 '22 18:10

Sparky


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?

like image 12
James Black Avatar answered Oct 18 '22 20:10

James Black


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:

  1. 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).

  2. 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.
like image 7
ZarathustrA Avatar answered Oct 18 '22 20:10

ZarathustrA