Using NMI to synchronize timestamp counter between cores?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
rdos
Member
Member
Posts: 3311
Joined: Wed Oct 01, 2008 1:55 pm

Using NMI to synchronize timestamp counter between cores?

Post by rdos »

I read up on all the different methods proposed for synchronizing time stamp counter (TSC) between cores. In my mini-PC that I currently target, this doesn't seem to be an issue at all since it only has an Intel Atom processor with hyperthreading. It probably has only a single TSC implemented. As I move on to my other PCs (one is a dual core AMD Athlon), I think the need for synchronization will arise. I have some trouble on that platform that could be related to TSC.

Anyway, NMI is an attractive option as it is non-maskable (predictable processing times), and the utility of the hardware NMI signal seems to be zero. First I would disable hardware NMI in the local Apic, just in case there is real hardware NMI activity.

Some possible implementation (in partial pseudocode):

In the null-thread before starting SMP (Measuring response-time for NMI handler):

Code: Select all

    rdtsc
    mov curr_time,eax
    int 2
On the BSP, start a timer:

Code: Select all

    GetSystemTime
    add eax,1193
    adc edx,0
    mov di,OFFSET sync_tsc
    StartTimer   ; invoke handler in 1 ms
In the timer handler (always runs on BSP):

Code: Select all

sync_tsc:
    rdtsc
    mov curr_time,eax
    SendNmiToAllExceptSelf  (send an IPI with an NMI to all cores except self)
    add eax,1193000
    adc edx,0
    mov di,OFFSET sync_tsc
    StartTimer   ; invoke again in 1s
AP code initialization:

Code: Select all

    cli
    hlt   (wait for NMI)
    jmp InitFirstThread
The NMI handler (less some register pushing / loads):

Code: Select all

    rdtsc
    sub eax,curr_time    
    GetProcessor
    mov fs:diff_time,eax
    iretd
The code that reads the timestamp would be modified to:

Code: Select all

    GetProcessor
    rdtsc
    add eax,fs:diff_time
Does this look reasonable?
Post Reply