(root)/
strace-6.5/
tests-mx32/
ioctl_rtc.c
       1  /*
       2   * Check decoding of RTC ioctl commands.
       3   *
       4   * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2022 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include <stdio.h>
      13  #include <stdlib.h>
      14  #include <string.h>
      15  #include <sys/ioctl.h>
      16  #include <linux/types.h>
      17  #include <linux/rtc.h>
      18  
      19  #ifndef RTC_VL_READ
      20  # define RTC_VL_READ _IOR('p', 0x13, unsigned int)
      21  #endif
      22  #ifndef RTC_VL_CLR
      23  # define RTC_VL_CLR _IO ('p', 0x14)
      24  #endif
      25  
      26  #ifndef RTC_PARAM_GET
      27  struct rtc_param {
      28  	__u64 param;
      29  	union {
      30  		__u64 uvalue;
      31  		__s64 svalue;
      32  		__u64 ptr;
      33  	};
      34  	__u32 index;
      35  	__u32 __pad;
      36  };
      37  # define RTC_PARAM_GET _IOW('p', 0x13, struct rtc_param)
      38  #endif /* !TC_PARAM_GET */
      39  #ifndef RTC_PARAM_SET
      40  # define RTC_PARAM_SET _IOW('p', 0x14, struct rtc_param)
      41  #endif
      42  
      43  static const unsigned long lmagic = (unsigned long) 0xdeadbeefbadc0dedULL;
      44  
      45  static const char *errstr;
      46  
      47  static int
      48  do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
      49  {
      50  	int rc = ioctl(-1, cmd, arg);
      51  	errstr = sprintrc(rc);
      52  
      53  #ifdef INJECT_RETVAL
      54  	if (rc != INJECT_RETVAL)
      55  		error_msg_and_fail("Return value [%d] does not match"
      56  				   " expectations [%d]", rc, INJECT_RETVAL);
      57  
      58  	static char inj_errstr[4096];
      59  
      60  	snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
      61  	errstr = inj_errstr;
      62  #endif
      63  
      64  	return rc;
      65  }
      66  
      67  static int
      68  do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
      69  {
      70  	return do_ioctl(cmd, (uintptr_t) arg);
      71  }
      72  
      73  #ifdef INJECT_RETVAL
      74  static void
      75  skip_ioctls(int argc, const char *argv[])
      76  {
      77  	if (argc < 2)
      78  		error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
      79  
      80  	unsigned long num_skip = strtoul(argv[1], NULL, 0);
      81  
      82  	for (size_t i = 0; i < num_skip; ++i) {
      83  		int rc = ioctl(-1, RTC_AIE_OFF, 0);
      84  		printf("ioctl(-1, RTC_AIE_OFF) = %s%s\n", sprintrc(rc),
      85  		       rc == INJECT_RETVAL ? " (INJECTED)" : "");
      86  		if (rc == INJECT_RETVAL)
      87  			return;
      88  	}
      89  
      90  	error_msg_and_fail("Issued %lu ioctl syscalls but failed"
      91  			   " to detect an injected return code %d",
      92  			   num_skip, INJECT_RETVAL);
      93  }
      94  #endif /* INJECT_RETVAL */
      95  
      96  static void
      97  print_rtc_time(const struct rtc_time *rt)
      98  {
      99  	printf("{tm_sec=%d, tm_min=%d, tm_hour=%d"
     100  	       ", tm_mday=%d, tm_mon=%d, tm_year=%d",
     101  	       rt->tm_sec, rt->tm_min, rt->tm_hour,
     102  	       rt->tm_mday, rt->tm_mon, rt->tm_year);
     103  #if VERBOSE
     104  	printf(", tm_wday=%d, tm_yday=%d, tm_isdst=%d}",
     105  	       rt->tm_wday, rt->tm_yday, rt->tm_isdst);
     106  #else
     107  	printf(", ...}");
     108  #endif
     109  }
     110  
     111  int
     112  main(int argc, const char *argv[])
     113  {
     114  #ifdef INJECT_RETVAL
     115  	skip_ioctls(argc, argv);
     116  #endif
     117  
     118  	static const struct {
     119  		unsigned int cmd;
     120  		const char *str;
     121  	} noarg_cmds[] = {
     122  		{ ARG_STR(RTC_AIE_OFF) },
     123  #ifdef HPPA
     124  		{ RTC_AIE_ON, "PA_PERF_ON or RTC_AIE_ON" },
     125  #else
     126  		{ ARG_STR(RTC_AIE_ON) },
     127  #endif
     128  		{ ARG_STR(RTC_PIE_OFF) },
     129  		{ ARG_STR(RTC_PIE_ON) },
     130  		{ RTC_UIE_OFF, "PHN_NOT_OH or RTC_UIE_OFF" },
     131  		{ ARG_STR(RTC_UIE_ON) },
     132  		{ ARG_STR(RTC_VL_CLR), },
     133  		{ ARG_STR(RTC_WIE_OFF) },
     134  		{ ARG_STR(RTC_WIE_ON) },
     135  	}, long_cmds[] = {
     136  		{ ARG_STR(RTC_EPOCH_SET) },
     137  		{ ARG_STR(RTC_IRQP_SET) },
     138  	}, plong_cmds[] = {
     139  		{ ARG_STR(RTC_EPOCH_READ) },
     140  		{ ARG_STR(RTC_IRQP_READ) },
     141  	}, ptr_cmds[] = {
     142  		{ ARG_STR(RTC_ALM_READ) },
     143  		{ ARG_STR(RTC_ALM_SET) },
     144  		{ ARG_STR(RTC_EPOCH_READ) },
     145  		{ ARG_STR(RTC_IRQP_READ) },
     146  		{ ARG_STR(RTC_PLL_GET) },
     147  		{ ARG_STR(RTC_PLL_SET) },
     148  		{ ARG_STR(RTC_RD_TIME) },
     149  		{ ARG_STR(RTC_SET_TIME) },
     150  		{ ARG_STR(RTC_VL_READ) },
     151  		{ ARG_STR(RTC_WKALM_RD) },
     152  		{ ARG_STR(RTC_WKALM_SET) },
     153  	}, r_time_cmds[] = {
     154  		{ ARG_STR(RTC_ALM_READ) },
     155  		{ ARG_STR(RTC_RD_TIME) },
     156  	}, w_time_cmds[] = {
     157  		{ ARG_STR(RTC_ALM_SET) },
     158  		{ ARG_STR(RTC_SET_TIME) },
     159  	}, r_wkalrm_cmds[] = {
     160  		{ ARG_STR(RTC_WKALM_RD) },
     161  	}, w_wkalrm_cmds[] = {
     162  		{ ARG_STR(RTC_WKALM_SET) },
     163  	}, r_pll_cmds[] = {
     164  		{ ARG_STR(RTC_PLL_GET) },
     165  	}, w_pll_cmds[] = {
     166  		{ ARG_STR(RTC_PLL_SET) },
     167  	};
     168  
     169  	for (size_t i = 0; i < ARRAY_SIZE(noarg_cmds); ++i) {
     170  		do_ioctl(noarg_cmds[i].cmd, lmagic);
     171  		printf("ioctl(-1, %s) = %s\n",
     172  		       noarg_cmds[i].str, errstr);
     173  	}
     174  
     175  	for (size_t i = 0; i < ARRAY_SIZE(long_cmds); ++i) {
     176  		do_ioctl(long_cmds[i].cmd, lmagic);
     177  		printf("ioctl(-1, %s, %lu) = %s\n",
     178  		       long_cmds[i].str, lmagic, errstr);
     179  	}
     180  
     181  	TAIL_ALLOC_OBJECT_CONST_PTR(unsigned long, plong);
     182  	*plong = lmagic;
     183  
     184  	for (size_t i = 0; i < ARRAY_SIZE(plong_cmds); ++i) {
     185  		if (do_ioctl_ptr(plong_cmds[i].cmd, plong) < 0) {
     186  			printf("ioctl(-1, %s, %p) = %s\n",
     187  			       plong_cmds[i].str, plong, errstr);
     188  		} else {
     189  			printf("ioctl(-1, %s, [%lu]) = %s\n",
     190  			       plong_cmds[i].str, *plong, errstr);
     191  		}
     192  	}
     193  
     194  	void *const efault = tail_alloc(1);
     195  
     196  	for (size_t i = 0; i < ARRAY_SIZE(ptr_cmds); ++i) {
     197  		do_ioctl(ptr_cmds[i].cmd, 0);
     198  		printf("ioctl(-1, %s, NULL) = %s\n",
     199  		       ptr_cmds[i].str, errstr);
     200  		do_ioctl_ptr(ptr_cmds[i].cmd, efault);
     201  		printf("ioctl(-1, %s, %p) = %s\n",
     202  		       ptr_cmds[i].str, efault, errstr);
     203  	}
     204  
     205  	TAIL_ALLOC_OBJECT_CONST_PTR(struct rtc_time, rt);
     206  	fill_memory(rt, sizeof(*rt));
     207  
     208  	for (size_t i = 0; i < ARRAY_SIZE(w_time_cmds); ++i) {
     209  		do_ioctl_ptr(w_time_cmds[i].cmd, rt);
     210  		printf("ioctl(-1, %s, ", w_time_cmds[i].str);
     211  		print_rtc_time(rt);
     212  		printf(") = %s\n", errstr);
     213  	}
     214  
     215  	for (size_t i = 0; i < ARRAY_SIZE(r_time_cmds); ++i) {
     216  		if (do_ioctl_ptr(r_time_cmds[i].cmd, rt) < 0) {
     217  			printf("ioctl(-1, %s, %p) = %s\n",
     218  			       r_time_cmds[i].str, rt, errstr);
     219  		} else {
     220  			printf("ioctl(-1, %s, ", r_time_cmds[i].str);
     221  			print_rtc_time(rt);
     222  			printf(") = %s\n", errstr);
     223  		}
     224  	}
     225  
     226  	TAIL_ALLOC_OBJECT_CONST_PTR(struct rtc_wkalrm, wk);
     227  	fill_memory(wk, sizeof(*wk));
     228  
     229  	for (size_t i = 0; i < ARRAY_SIZE(w_wkalrm_cmds); ++i) {
     230  		do_ioctl_ptr(w_wkalrm_cmds[i].cmd, wk);
     231  		printf("ioctl(-1, %s, {enabled=%hhu, pending=%hhu, time=",
     232  		       w_wkalrm_cmds[i].str, wk->enabled, wk->pending);
     233  		print_rtc_time(&wk->time);
     234  		printf("}) = %s\n", errstr);
     235  	}
     236  
     237  	for (size_t i = 0; i < ARRAY_SIZE(r_wkalrm_cmds); ++i) {
     238  		if (do_ioctl_ptr(r_wkalrm_cmds[i].cmd, wk) < 0) {
     239  			printf("ioctl(-1, %s, %p) = %s\n",
     240  			       r_wkalrm_cmds[i].str, wk, errstr);
     241  		} else {
     242  			printf("ioctl(-1, %s, {enabled=%hhu, pending=%hhu, time=",
     243  			       r_wkalrm_cmds[i].str, wk->enabled, wk->pending);
     244  			print_rtc_time(&wk->time);
     245  			printf("}) = %s\n", errstr);
     246  		}
     247  	}
     248  
     249  	TAIL_ALLOC_OBJECT_CONST_PTR(struct rtc_pll_info, pll);
     250  	fill_memory(pll, sizeof(*pll));
     251  
     252  	for (size_t i = 0; i < ARRAY_SIZE(w_pll_cmds); ++i) {
     253  		do_ioctl_ptr(w_pll_cmds[i].cmd, pll);
     254  		printf("ioctl(-1, %s, {pll_ctrl=%d, pll_value=%d"
     255  		       ", pll_max=%d, pll_min=%d, pll_posmult=%d"
     256  		       ", pll_negmult=%d, pll_clock=%ld}) = %s\n",
     257  		       w_pll_cmds[i].str, pll->pll_ctrl, pll->pll_value,
     258  		       pll->pll_max, pll->pll_min, pll->pll_posmult,
     259  		       pll->pll_negmult, pll->pll_clock, errstr);
     260  	}
     261  
     262  	for (size_t i = 0; i < ARRAY_SIZE(r_pll_cmds); ++i) {
     263  		if (do_ioctl_ptr(r_pll_cmds[i].cmd, pll) < 0) {
     264  			printf("ioctl(-1, %s, %p) = %s\n",
     265  			       r_pll_cmds[i].str, pll, errstr);
     266  		} else {
     267  			printf("ioctl(-1, %s, {pll_ctrl=%d, pll_value=%d"
     268  			       ", pll_max=%d, pll_min=%d, pll_posmult=%d"
     269  			       ", pll_negmult=%d, pll_clock=%ld}) = %s\n",
     270  			       r_pll_cmds[i].str, pll->pll_ctrl, pll->pll_value,
     271  			       pll->pll_max, pll->pll_min, pll->pll_posmult,
     272  			       pll->pll_negmult, pll->pll_clock, errstr);
     273  		}
     274  	}
     275  
     276  	static const struct strval32 vl_vecs[] = {
     277  		{ ARG_STR(0) },
     278  		{ ARG_XLAT_KNOWN(0x10, "RTC_VL_BACKUP_SWITCH") },
     279  		{ ARG_XLAT_KNOWN(0xbeef, "RTC_VL_DATA_INVALID"
     280  					 "|RTC_VL_BACKUP_LOW"
     281  					 "|RTC_VL_BACKUP_EMPTY"
     282  					 "|RTC_VL_ACCURACY_LOW|0xbee0") },
     283  		{ ARG_XLAT_UNKNOWN(0xbadc0de0, "RTC_VL_???") },
     284  	};
     285  	TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, pint);
     286  
     287  	for (size_t i = 0; i < ARRAY_SIZE(vl_vecs); i++) {
     288  		*pint = vl_vecs[i].val;
     289  
     290  		if (do_ioctl_ptr(RTC_VL_READ, pint) < 0) {
     291  			printf("ioctl(-1, RTC_VL_READ, %p) = %s\n",
     292  			       pint, errstr);
     293  		} else {
     294  			printf("ioctl(-1, RTC_VL_READ, [%s]) = %s\n",
     295  			       vl_vecs[i].str, errstr);
     296  		}
     297  	}
     298  
     299  	do_ioctl(_IO(0x70, 0x40), lmagic);
     300  	printf("ioctl(-1, %s, %#lx) = %s\n", "NVRAM_INIT", lmagic, errstr);
     301  
     302  	static const struct strval32 param_cmds[] = {
     303  		{ ARG_STR(RTC_PARAM_GET) },
     304  		{ ARG_STR(RTC_PARAM_SET) },
     305  	};
     306  	static const struct {
     307  		struct rtc_param val;
     308  		const char *get_in;
     309  		const char *get_out;
     310  		const char *set;
     311  	} param_vecs[] = {
     312  		{ { 0 },
     313  		  "{param=RTC_PARAM_FEATURES, index=0}",
     314  		  "{uvalue=0}",
     315  		  "{param=RTC_PARAM_FEATURES, uvalue=0, index=0}" },
     316  		{ { .param = 0, .uvalue = (__u64) 0xdeadfacebeeffeedULL,
     317  		    .index= 0xfacecafe, .__pad = 0xbadc0ded },
     318  		  "{param=RTC_PARAM_FEATURES, index=4207856382"
     319  		  ", __pad=0xbadc0ded}",
     320  		  "{uvalue=1<<RTC_FEATURE_ALARM|1<<RTC_FEATURE_NEED_WEEK_DAY"
     321  		  "|1<<RTC_FEATURE_ALARM_RES_2S|1<<RTC_FEATURE_CORRECTION"
     322  		  "|1<<RTC_FEATURE_BACKUP_SWITCH_MODE"
     323  		  "|1<<RTC_FEATURE_ALARM_WAKEUP_ONLY|0xdeadfacebeeffe00"
     324  		  ", __pad=0xbadc0ded}",
     325  		  "{param=RTC_PARAM_FEATURES, uvalue=1<<RTC_FEATURE_ALARM"
     326  		  "|1<<RTC_FEATURE_NEED_WEEK_DAY|1<<RTC_FEATURE_ALARM_RES_2S"
     327  		  "|1<<RTC_FEATURE_CORRECTION|1<<RTC_FEATURE_BACKUP_SWITCH_MODE"
     328  		  "|1<<RTC_FEATURE_ALARM_WAKEUP_ONLY|0xdeadfacebeeffe00"
     329  		  ", index=4207856382, __pad=0xbadc0ded}" },
     330  		{ { .param = 0, .uvalue = 0xbeef00, .__pad = 1 },
     331  		  "{param=RTC_PARAM_FEATURES, index=0, __pad=0x1}",
     332  		  "{uvalue=0xbeef00 /* 1<<RTC_FEATURE_??? */, __pad=0x1}",
     333  		  "{param=RTC_PARAM_FEATURES"
     334  		  ", uvalue=0xbeef00 /* 1<<RTC_FEATURE_??? */, index=0"
     335  		  ", __pad=0x1}" },
     336  		{ { .param = 1 },
     337  		  "{param=RTC_PARAM_CORRECTION, index=0}",
     338  		  "{svalue=0}",
     339  		  "{param=RTC_PARAM_CORRECTION, svalue=0, index=0}" },
     340  		{ { .param = 1, .svalue = (__s64) 0xfacefeeddeadcafeULL,
     341  		    .index = 0xdeffaced, .__pad = 0xcafeface },
     342  		  "{param=RTC_PARAM_CORRECTION, index=3741297901"
     343  		  ", __pad=0xcafeface}",
     344  		  "{svalue=-374081421428536578, __pad=0xcafeface}",
     345  		  "{param=RTC_PARAM_CORRECTION, svalue=-374081421428536578"
     346  		  ", index=3741297901, __pad=0xcafeface}" },
     347  		{ { .param = 1, .svalue = -1337, .index = 0x42 },
     348  		  "{param=RTC_PARAM_CORRECTION, index=66}",
     349  		  "{svalue=-1337}",
     350  		  "{param=RTC_PARAM_CORRECTION, svalue=-1337, index=66}" },
     351  		{ { .param = 2 },
     352  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, index=0}",
     353  		  "{uvalue=RTC_BSM_DISABLED}",
     354  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, uvalue=RTC_BSM_DISABLED"
     355  		  ", index=0}" },
     356  		{ { .param = 2, .uvalue = 3, .index = 0xdecaffed,
     357  		    .__pad = 0xfacebeef },
     358  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, index=3737845741"
     359  		  ", __pad=0xfacebeef}",
     360  		  "{uvalue=RTC_BSM_STANDBY, __pad=0xfacebeef}",
     361  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, uvalue=RTC_BSM_STANDBY"
     362  		  ", index=3737845741, __pad=0xfacebeef}" },
     363  		{ { .param = 2, .uvalue = 4, .__pad = 23 },
     364  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, index=0, __pad=0x17}",
     365  		  "{uvalue=0x4 /* RTC_BSM_??? */, __pad=0x17}",
     366  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE"
     367  		  ", uvalue=0x4 /* RTC_BSM_??? */, index=0, __pad=0x17}" },
     368  		{ { .param = 2, .uvalue = (__u64) 0xface1e55beefcafeULL,
     369  		    .index = 42 },
     370  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE, index=42}",
     371  		  "{uvalue=0xface1e55beefcafe /* RTC_BSM_??? */}",
     372  		  "{param=RTC_PARAM_BACKUP_SWITCH_MODE"
     373  		  ", uvalue=0xface1e55beefcafe /* RTC_BSM_??? */"
     374  		  ", index=42}" },
     375  		{ { .param = 3 },
     376  		  "{param=0x3 /* RTC_PARAM_??? */, index=0}",
     377  		  "{uvalue=0}",
     378  		  "{param=0x3 /* RTC_PARAM_??? */, uvalue=0, index=0}" },
     379  		{ { .param = (__u64) 0xbeeffacedeadc0deULL,
     380  		    .uvalue = (__u64) 0xdefc0dedbadfacedULL,
     381  		    .index = 3141592653, .__pad = 2718281828 },
     382  		  "{param=0xbeeffacedeadc0de /* RTC_PARAM_??? */"
     383  		  ", index=3141592653, __pad=0xa205b064}",
     384  		  "{uvalue=0xdefc0dedbadfaced, __pad=0xa205b064}",
     385  		  "{param=0xbeeffacedeadc0de /* RTC_PARAM_??? */"
     386  		  ", uvalue=0xdefc0dedbadfaced, index=3141592653"
     387  		  ", __pad=0xa205b064}" },
     388  	};
     389  	TAIL_ALLOC_OBJECT_CONST_PTR(struct rtc_param, pparam);
     390  
     391  	for (size_t i = 0; i < ARRAY_SIZE(param_cmds); i++) {
     392  		do_ioctl(param_cmds[i].val, 0);
     393  		printf("ioctl(-1, %s, NULL) = %s\n",
     394  		       param_cmds[i].str, errstr);
     395  
     396  		do_ioctl_ptr(param_cmds[i].val, pparam + 1);
     397  		printf("ioctl(-1, %s, %p) = %s\n",
     398  		       param_cmds[i].str, pparam + 1, errstr);
     399  	}
     400  
     401  	for (size_t i = 0; i < ARRAY_SIZE(param_vecs); i++) {
     402  		*pparam = param_vecs[i].val;
     403  
     404  		int ret = do_ioctl_ptr(RTC_PARAM_GET, pparam);
     405  		printf("ioctl(-1, RTC_PARAM_GET, %s => ", param_vecs[i].get_in);
     406  		if (ret < 0)
     407  			printf("%p", pparam);
     408  		else
     409  			printf("%s", param_vecs[i].get_out);
     410  		printf(") = %s\n", errstr);
     411  
     412  		do_ioctl_ptr(RTC_PARAM_SET, pparam);
     413  		printf("ioctl(-1, RTC_PARAM_SET, %s) = %s\n",
     414  		       param_vecs[i].set, errstr);
     415  	}
     416  
     417  	puts("+++ exited with 0 +++");
     418  	return 0;
     419  }