Implementation of the nanokernel modifications involves two steps. The first is to verify the new kernel tick interrupt and PPS interrupt source code is compatible with the particular machine architecture, operating system and compiler. The kern simulator program is designed to do this using the actual kernel code fragments in both 32-and 64-bit architectures and with both microsecond and nanosecond kernel time variables. See the kern.h, timex.h and l_fp.h header files, the NANO and L64 defines, and accompanying commentary. See the description of the kern simulator program for directions on its use. Use the test.sh script to compile and test the simulator. This script uses the gcc compiler, but an ordinary cc compiler should work as well. Use the kern.dat script to simulate and test the code fragments throughout the complete operational envelope.
The second step is to extract the relevant code fragments from the ktime.c and micro.c source files and insert in the kernel source code. The ktime.c file in most cases can be used almost as-is, with linkages established from the BSD hardclock() routine or equivalent to service the tick interrupt and to the kernel routine to read the system clock and interpolate the nanoseconds or microseconds. The ntp_tick_adjust() routine replaces the code that increments the system clock by the tick interval, while the second_overflow() routine is called just after the test for seconds overflow. Typical modifications in this code are to the various copy-in and copy-out interfaces, set-priority calls and return codes.
Each architecture may have a different method to read the system clock as an atomic operation and to interpolate the nanoseconds or microseconds. The routines in the micro.c source file serve as typical examples, but these work only in 64-bit architectures. In the case of symmetric multiprocessor (SMP) systems, the implementation involves a special interprocessor interrupt about once per second for each processor, in order to calibrate the nanosecond interpolation and establish a base time and oscillator rate. The interrupt should be initiated from the tick interrupt routine after the routines in the ktime.c source file. From experience, this code is extremely delicate and requires very careful consideration for overflows, etc., that can happen in various places. The micro.c code was tested thoroughly in simulation, during which several oversights and undersights were found and corrected. See the commentary for specific considerations.
The PPS signal interfacing issues are beyond the scope of this discussion; however, the prudent course would be to modify the hardware driver to capture transitions of a modem control lead such as DCD and call the nano_time_rpcc() routine in micro.c, then pass the results on to hardpps() in ktime.c. Following is a code snip showing how this can be done:
struct timespec pps_time; long nsec; if (!edge) return; nsec = nano_time_rpcc(&pps_time); hardpps(&pps_time, nsec);
One of the things to watch for in this code is the possibility that a modem control lead interrupt can in some architectures preempt a timer interrupt. The problem occurs when the modem interrupt and call to hardpps() occurs before the ntp_tick_adjust() routine is called from hardclock(). While the hardpps() routine has been coded with this possibility in mind, it helps to move the ntp_tick_adjust() call as early in the hardclock() routine as possible.
Stay tuned for an IETF application program interface document on PPS API.