18c2ecf20Sopenharmony_ci/* valid adjtimex test 28c2ecf20Sopenharmony_ci * by: John Stultz <john.stultz@linaro.org> 38c2ecf20Sopenharmony_ci * (C) Copyright Linaro 2015 48c2ecf20Sopenharmony_ci * Licensed under the GPLv2 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This test validates adjtimex interface with valid 78c2ecf20Sopenharmony_ci * and invalid test data. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Usage: valid-adjtimex 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * To build: 128c2ecf20Sopenharmony_ci * $ gcc valid-adjtimex.c -o valid-adjtimex -lrt 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 158c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 168c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 178c2ecf20Sopenharmony_ci * (at your option) any later version. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 208c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 218c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 228c2ecf20Sopenharmony_ci * GNU General Public License for more details. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include <stdio.h> 288c2ecf20Sopenharmony_ci#include <stdlib.h> 298c2ecf20Sopenharmony_ci#include <time.h> 308c2ecf20Sopenharmony_ci#include <sys/time.h> 318c2ecf20Sopenharmony_ci#include <sys/timex.h> 328c2ecf20Sopenharmony_ci#include <string.h> 338c2ecf20Sopenharmony_ci#include <signal.h> 348c2ecf20Sopenharmony_ci#include <unistd.h> 358c2ecf20Sopenharmony_ci#include "../kselftest.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000LL 388c2ecf20Sopenharmony_ci#define USEC_PER_SEC 1000000LL 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define ADJ_SETOFFSET 0x0100 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <sys/syscall.h> 438c2ecf20Sopenharmony_ciint clock_adjtime(clockid_t id, struct timex *tx) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return syscall(__NR_clock_adjtime, id, tx); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* clear NTP time_status & time_state */ 508c2ecf20Sopenharmony_ciint clear_time_state(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct timex tx; 538c2ecf20Sopenharmony_ci int ret; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci tx.modes = ADJ_STATUS; 568c2ecf20Sopenharmony_ci tx.status = 0; 578c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define NUM_FREQ_VALID 32 628c2ecf20Sopenharmony_ci#define NUM_FREQ_OUTOFRANGE 4 638c2ecf20Sopenharmony_ci#define NUM_FREQ_INVALID 2 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cilong valid_freq[NUM_FREQ_VALID] = { 668c2ecf20Sopenharmony_ci -499<<16, 678c2ecf20Sopenharmony_ci -450<<16, 688c2ecf20Sopenharmony_ci -400<<16, 698c2ecf20Sopenharmony_ci -350<<16, 708c2ecf20Sopenharmony_ci -300<<16, 718c2ecf20Sopenharmony_ci -250<<16, 728c2ecf20Sopenharmony_ci -200<<16, 738c2ecf20Sopenharmony_ci -150<<16, 748c2ecf20Sopenharmony_ci -100<<16, 758c2ecf20Sopenharmony_ci -75<<16, 768c2ecf20Sopenharmony_ci -50<<16, 778c2ecf20Sopenharmony_ci -25<<16, 788c2ecf20Sopenharmony_ci -10<<16, 798c2ecf20Sopenharmony_ci -5<<16, 808c2ecf20Sopenharmony_ci -1<<16, 818c2ecf20Sopenharmony_ci -1000, 828c2ecf20Sopenharmony_ci 1<<16, 838c2ecf20Sopenharmony_ci 5<<16, 848c2ecf20Sopenharmony_ci 10<<16, 858c2ecf20Sopenharmony_ci 25<<16, 868c2ecf20Sopenharmony_ci 50<<16, 878c2ecf20Sopenharmony_ci 75<<16, 888c2ecf20Sopenharmony_ci 100<<16, 898c2ecf20Sopenharmony_ci 150<<16, 908c2ecf20Sopenharmony_ci 200<<16, 918c2ecf20Sopenharmony_ci 250<<16, 928c2ecf20Sopenharmony_ci 300<<16, 938c2ecf20Sopenharmony_ci 350<<16, 948c2ecf20Sopenharmony_ci 400<<16, 958c2ecf20Sopenharmony_ci 450<<16, 968c2ecf20Sopenharmony_ci 499<<16, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cilong outofrange_freq[NUM_FREQ_OUTOFRANGE] = { 1008c2ecf20Sopenharmony_ci -1000<<16, 1018c2ecf20Sopenharmony_ci -550<<16, 1028c2ecf20Sopenharmony_ci 550<<16, 1038c2ecf20Sopenharmony_ci 1000<<16, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define LONG_MAX (~0UL>>1) 1078c2ecf20Sopenharmony_ci#define LONG_MIN (-LONG_MAX - 1) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cilong invalid_freq[NUM_FREQ_INVALID] = { 1108c2ecf20Sopenharmony_ci LONG_MAX, 1118c2ecf20Sopenharmony_ci LONG_MIN, 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint validate_freq(void) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct timex tx; 1178c2ecf20Sopenharmony_ci int ret, pass = 0; 1188c2ecf20Sopenharmony_ci int i; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci clear_time_state(); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci memset(&tx, 0, sizeof(struct timex)); 1238c2ecf20Sopenharmony_ci /* Set the leap second insert flag */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci printf("Testing ADJ_FREQ... "); 1268c2ecf20Sopenharmony_ci fflush(stdout); 1278c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FREQ_VALID; i++) { 1288c2ecf20Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 1298c2ecf20Sopenharmony_ci tx.freq = valid_freq[i]; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1328c2ecf20Sopenharmony_ci if (ret < 0) { 1338c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1348c2ecf20Sopenharmony_ci printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", 1358c2ecf20Sopenharmony_ci valid_freq[i], valid_freq[i]>>16); 1368c2ecf20Sopenharmony_ci pass = -1; 1378c2ecf20Sopenharmony_ci goto out; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci tx.modes = 0; 1408c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1418c2ecf20Sopenharmony_ci if (tx.freq != valid_freq[i]) { 1428c2ecf20Sopenharmony_ci printf("Warning: freq value %ld not what we set it (%ld)!\n", 1438c2ecf20Sopenharmony_ci tx.freq, valid_freq[i]); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) { 1478c2ecf20Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 1488c2ecf20Sopenharmony_ci tx.freq = outofrange_freq[i]; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1518c2ecf20Sopenharmony_ci if (ret < 0) { 1528c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1538c2ecf20Sopenharmony_ci printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n", 1548c2ecf20Sopenharmony_ci outofrange_freq[i], outofrange_freq[i]>>16); 1558c2ecf20Sopenharmony_ci pass = -1; 1568c2ecf20Sopenharmony_ci goto out; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci tx.modes = 0; 1598c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1608c2ecf20Sopenharmony_ci if (tx.freq == outofrange_freq[i]) { 1618c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1628c2ecf20Sopenharmony_ci printf("ERROR: out of range value %ld actually set!\n", 1638c2ecf20Sopenharmony_ci tx.freq); 1648c2ecf20Sopenharmony_ci pass = -1; 1658c2ecf20Sopenharmony_ci goto out; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (sizeof(long) == 8) { /* this case only applies to 64bit systems */ 1718c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FREQ_INVALID; i++) { 1728c2ecf20Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 1738c2ecf20Sopenharmony_ci tx.freq = invalid_freq[i]; 1748c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1758c2ecf20Sopenharmony_ci if (ret >= 0) { 1768c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1778c2ecf20Sopenharmony_ci printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n", 1788c2ecf20Sopenharmony_ci invalid_freq[i]); 1798c2ecf20Sopenharmony_ci pass = -1; 1808c2ecf20Sopenharmony_ci goto out; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci printf("[OK]\n"); 1868c2ecf20Sopenharmony_ciout: 1878c2ecf20Sopenharmony_ci /* reset freq to zero */ 1888c2ecf20Sopenharmony_ci tx.modes = ADJ_FREQUENCY; 1898c2ecf20Sopenharmony_ci tx.freq = 0; 1908c2ecf20Sopenharmony_ci ret = adjtimex(&tx); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return pass; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciint set_offset(long long offset, int use_nano) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct timex tmx = {}; 1998c2ecf20Sopenharmony_ci int ret; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci tmx.modes = ADJ_SETOFFSET; 2028c2ecf20Sopenharmony_ci if (use_nano) { 2038c2ecf20Sopenharmony_ci tmx.modes |= ADJ_NANO; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci tmx.time.tv_sec = offset / NSEC_PER_SEC; 2068c2ecf20Sopenharmony_ci tmx.time.tv_usec = offset % NSEC_PER_SEC; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (offset < 0 && tmx.time.tv_usec) { 2098c2ecf20Sopenharmony_ci tmx.time.tv_sec -= 1; 2108c2ecf20Sopenharmony_ci tmx.time.tv_usec += NSEC_PER_SEC; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci tmx.time.tv_sec = offset / USEC_PER_SEC; 2148c2ecf20Sopenharmony_ci tmx.time.tv_usec = offset % USEC_PER_SEC; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (offset < 0 && tmx.time.tv_usec) { 2178c2ecf20Sopenharmony_ci tmx.time.tv_sec -= 1; 2188c2ecf20Sopenharmony_ci tmx.time.tv_usec += USEC_PER_SEC; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ret = clock_adjtime(CLOCK_REALTIME, &tmx); 2238c2ecf20Sopenharmony_ci if (ret < 0) { 2248c2ecf20Sopenharmony_ci printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec); 2258c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 2268c2ecf20Sopenharmony_ci return -1; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciint set_bad_offset(long sec, long usec, int use_nano) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct timex tmx = {}; 2348c2ecf20Sopenharmony_ci int ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci tmx.modes = ADJ_SETOFFSET; 2378c2ecf20Sopenharmony_ci if (use_nano) 2388c2ecf20Sopenharmony_ci tmx.modes |= ADJ_NANO; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci tmx.time.tv_sec = sec; 2418c2ecf20Sopenharmony_ci tmx.time.tv_usec = usec; 2428c2ecf20Sopenharmony_ci ret = clock_adjtime(CLOCK_REALTIME, &tmx); 2438c2ecf20Sopenharmony_ci if (ret >= 0) { 2448c2ecf20Sopenharmony_ci printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec); 2458c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 2468c2ecf20Sopenharmony_ci return -1; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint validate_set_offset(void) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci printf("Testing ADJ_SETOFFSET... "); 2548c2ecf20Sopenharmony_ci fflush(stdout); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* Test valid values */ 2578c2ecf20Sopenharmony_ci if (set_offset(NSEC_PER_SEC - 1, 1)) 2588c2ecf20Sopenharmony_ci return -1; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (set_offset(-NSEC_PER_SEC + 1, 1)) 2618c2ecf20Sopenharmony_ci return -1; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (set_offset(-NSEC_PER_SEC - 1, 1)) 2648c2ecf20Sopenharmony_ci return -1; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (set_offset(5 * NSEC_PER_SEC, 1)) 2678c2ecf20Sopenharmony_ci return -1; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (set_offset(-5 * NSEC_PER_SEC, 1)) 2708c2ecf20Sopenharmony_ci return -1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1)) 2738c2ecf20Sopenharmony_ci return -1; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1)) 2768c2ecf20Sopenharmony_ci return -1; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (set_offset(USEC_PER_SEC - 1, 0)) 2798c2ecf20Sopenharmony_ci return -1; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (set_offset(-USEC_PER_SEC + 1, 0)) 2828c2ecf20Sopenharmony_ci return -1; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (set_offset(-USEC_PER_SEC - 1, 0)) 2858c2ecf20Sopenharmony_ci return -1; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (set_offset(5 * USEC_PER_SEC, 0)) 2888c2ecf20Sopenharmony_ci return -1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (set_offset(-5 * USEC_PER_SEC, 0)) 2918c2ecf20Sopenharmony_ci return -1; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0)) 2948c2ecf20Sopenharmony_ci return -1; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0)) 2978c2ecf20Sopenharmony_ci return -1; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Test invalid values */ 3008c2ecf20Sopenharmony_ci if (set_bad_offset(0, -1, 1)) 3018c2ecf20Sopenharmony_ci return -1; 3028c2ecf20Sopenharmony_ci if (set_bad_offset(0, -1, 0)) 3038c2ecf20Sopenharmony_ci return -1; 3048c2ecf20Sopenharmony_ci if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1)) 3058c2ecf20Sopenharmony_ci return -1; 3068c2ecf20Sopenharmony_ci if (set_bad_offset(0, 2 * USEC_PER_SEC, 0)) 3078c2ecf20Sopenharmony_ci return -1; 3088c2ecf20Sopenharmony_ci if (set_bad_offset(0, NSEC_PER_SEC, 1)) 3098c2ecf20Sopenharmony_ci return -1; 3108c2ecf20Sopenharmony_ci if (set_bad_offset(0, USEC_PER_SEC, 0)) 3118c2ecf20Sopenharmony_ci return -1; 3128c2ecf20Sopenharmony_ci if (set_bad_offset(0, -NSEC_PER_SEC, 1)) 3138c2ecf20Sopenharmony_ci return -1; 3148c2ecf20Sopenharmony_ci if (set_bad_offset(0, -USEC_PER_SEC, 0)) 3158c2ecf20Sopenharmony_ci return -1; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci printf("[OK]\n"); 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciint main(int argc, char **argv) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci if (validate_freq()) 3248c2ecf20Sopenharmony_ci return ksft_exit_fail(); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (validate_set_offset()) 3278c2ecf20Sopenharmony_ci return ksft_exit_fail(); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return ksft_exit_pass(); 3308c2ecf20Sopenharmony_ci} 331