Hi,
It works fine but i'm wondering how to send irq0 to all cpus?
It's good to be curious and experiment (but I wouldn't recommend broadcasting IRQ0 to all CPUs as part of any OS design)...
Kicer wrote:2. i think i could use logical mode in io apic and then use set of local apic ids in destination field, but i'm not quite sure how does it work.
the second idea seems to be better, but as i said i don't know how to use it.
First I should point out that there's a "cluster mode" and a "flat mode". The cluster mode is used for NUMA machines that have special APIC controllers between NUMA nodes, and isn't used for normal computers (including AMD's "ccNUMA" computers). I'll only be describing "flat mode" here - whether or not it's worth supporting cluster mode can be left for another discussion. There's also a new "x2APIC" that supersedes the "xAPIC" (which superseded the original APIC) - I won't be describing x2APIC either (I haven't had a chance to play with it yet
).
Basically (for logical destination mode), take the "Logical Destination Address" from where-ever the IRQ came from (e.g. from the I/O APIC redirection table entry's "Destination Field" in bits 56 to 63) and AND it with the local APIC's "Logical APIC ID". If any bits are still set, then the CPU can receive the IRQ.
This means that if you've got 8 CPUs you could have a different bit set in each local APIC's "Logical APIC ID", and you'd be able to select any number of CPUs by setting the corresponding bits in the "Logical Destination Address".
For example, if each CPU's "Logical APIC ID" is set like this:
- CPU0_logical_ID = 00000001b
CPU1_logical_ID = 00000010b
CPU2_logical_ID = 00000100b
CPU3_logical_ID = 00001000b
CPU4_logical_ID = 00010000b
CPU5_logical_ID = 00100000b
CPU6_logical_ID = 01000000b
CPU7_logical_ID = 10000000b
Then:
- If logical_destination = 00000001b, then interrupt sent to CPU0
If logical_destination = 00001000b, then interrupt sent to CPU3
If logical_destination = 01100000b, then interrupt sent to CPU5 and CPU6
If logical_destination = 00001111b, then interrupt sent to CPU0, CPU1, CPU2 and CPU3
If logical_destination = 11111111b, then interrupt sent to all CPUs
However, this may or may not suit your purposes. The big problem here is that you run out of bits when there's more than 8 CPUs present.
For larger systems you need something smarter. To do something smarter you need to figure out why interrupts are being sent and where they're being sent; and based on that information decide what each bit in the "Logical Destination Address" will be used for.
The other thing I should mention is that the same stuff ("Logical APIC IDs" and "Logical Destination Address") is also used for "send to lowest priority" interrupts (it's not just for broadcast interrupts). The "send to lowest priority" delivery mode can be useful for IRQs - for e.g. so that an IRQ is sent to a CPU that is idle instead of being sent to a CPU that's doing important work (and maybe instead of being sent to a CPU that's in a power saving state).
Kicer wrote:Or maybe there are some other options ?
The other option (for hardware IRQs and IPIs) is to use physical destination mode with the destination APIC ID set to 0xFF, which will broadcast the interrupt to every CPU. Also, for IPIs (but not IRQs) there's a few shorthand modes - "send to self", "send to all including self" and "send to all excluding self".
Cheers,
Brendan