Search code examples
clinux-kernelx86intelsmp

How to correctly use a startup-ipi to start an application processor?


My goal is to let my own kernel start an application cpu. It uses the same mechanism as the linux kernel:

  • Send asserting and level triggered init-IPI
  • Wait...
  • Send deasserting and level triggered init-IPI
  • Wait...
  • Send up to two startup-IPIs with vector number (0x40000 >> 12) (the entry code for the application processor lies there)

Currently I'm just interested in making it work with QEMU. Unfortunately, instead of jumping to 0x40000, the application cpu jumps to 0x0 with the cs register set to 0x4000. (I checked with gdb).

The Intel MultiProcessor Specification (B.4.2) explains that the behavior that I noticed is valid if the target processor is halted immediately after RESET or INIT. But shouldn't this also apply to the code of the linux kernel? It sends the startup-IPI after the init-IPI. Or do I misunderstand the specification?

What can I do to have the application processor jump to 0x000VV000 and not to 0x0 with the cs register set to 0xVV00? I really can't see, where linux does something that changes the behavior.


Solution

  • It seems that I really misunderstood the specification: Since the application cpu is started in real mode 0x000VV000 is equivalent to 0xVV00:0x0000. It is not possible to represent the address just in the 16 bit ip register. Therefore a segment offset for the code segment is required.

    Additionally, debugging real mode code with gdb is comparable complicated because it does not respect the segment offset. When required to see the disassembled code of the trampoline at the current position, it is necessary to calculate the physical location:

    x/20i $eip+0xVV000
    

    This makes gdb print the next 20 instructions at 0xVV00:$eip.