1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2003 4 * Tait Electronics Limited, Christchurch, New Zealand 5 */ 6 7 /* 8 * This file provides a shell like 'test' function to return 9 * true/false from an integer or string compare of two memory 10 * locations or a location and a scalar/literal. 11 * A few parts were lifted from bash 'test' command 12 */ 13 14 #include <common.h> 15 #include <config.h> 16 #include <command.h> 17 #include <mapmem.h> 18 19 #include <asm/io.h> 20 21 #define EQ 0 22 #define NE 1 23 #define LT 2 24 #define GT 3 25 #define LE 4 26 #define GE 5 27 28 struct op_tbl_s { 29 char *op; /* operator string */ 30 int opcode; /* internal representation of opcode */ 31 }; 32 33 typedef struct op_tbl_s op_tbl_t; 34 35 static const op_tbl_t op_table [] = { 36 { "-lt", LT }, 37 { "<" , LT }, 38 { "-gt", GT }, 39 { ">" , GT }, 40 { "-eq", EQ }, 41 { "==" , EQ }, 42 { "-ne", NE }, 43 { "!=" , NE }, 44 { "<>" , NE }, 45 { "-ge", GE }, 46 { ">=" , GE }, 47 { "-le", LE }, 48 { "<=" , LE }, 49 }; 50 51 static long evalexp(char *s, int w) 52 { 53 long l = 0; 54 unsigned long addr; 55 void *buf; 56 57 /* if the parameter starts with a * then assume is a pointer to the value we want */ 58 if (s[0] == '*') { 59 addr = simple_strtoul(&s[1], NULL, 16); 60 buf = map_physmem(addr, w, MAP_WRBACK); 61 if (!buf && addr) { 62 puts("Failed to map physical memory\n"); 63 return 0; 64 } 65 switch (w) { 66 case 1: 67 l = (long)(*(u8 *)buf); 68 break; 69 case 2: 70 l = (long)(*(u16 *)buf); 71 break; 72 case 4: 73 l = (long)(*(u32 *)buf); 74 break; 75 } 76 unmap_physmem(buf, w); 77 return l; 78 } else { 79 l = simple_strtoul(s, NULL, 16); 80 } 81 82 /* avoid overflow on mask calculus */ 83 return (w >= sizeof(long)) ? l : (l & ((1UL << (w * 8)) - 1)); 84 } 85 86 static char * evalstr(char *s) 87 { 88 /* if the parameter starts with a * then assume a string pointer else its a literal */ 89 if (s[0] == '*') { 90 return (char *)simple_strtoul(&s[1], NULL, 16); 91 } else if (s[0] == '$') { 92 int i = 2; 93 94 if (s[1] != '{') 95 return NULL; 96 97 while (s[i] != '}') { 98 if (s[i] == 0) 99 return NULL; 100 i++; 101 } 102 s[i] = 0; 103 return env_get((const char *)&s[2]); 104 } else { 105 return s; 106 } 107 } 108 109 static int stringcomp(char *s, char *t, int op) 110 { 111 int p; 112 char *l, *r; 113 114 l = evalstr(s); 115 r = evalstr(t); 116 117 p = strcmp(l, r); 118 switch (op) { 119 case EQ: return (p == 0); 120 case NE: return (p != 0); 121 case LT: return (p < 0); 122 case GT: return (p > 0); 123 case LE: return (p <= 0); 124 case GE: return (p >= 0); 125 } 126 return (0); 127 } 128 129 static int arithcomp (char *s, char *t, int op, int w) 130 { 131 long l, r; 132 133 l = evalexp (s, w); 134 r = evalexp (t, w); 135 136 switch (op) { 137 case EQ: return (l == r); 138 case NE: return (l != r); 139 case LT: return (l < r); 140 case GT: return (l > r); 141 case LE: return (l <= r); 142 case GE: return (l >= r); 143 } 144 return (0); 145 } 146 147 static int binary_test(char *op, char *arg1, char *arg2, int w) 148 { 149 int len, i; 150 const op_tbl_t *optp; 151 152 len = strlen(op); 153 154 for (optp = (op_tbl_t *)&op_table, i = 0; 155 i < ARRAY_SIZE(op_table); 156 optp++, i++) { 157 158 if ((strncmp (op, optp->op, len) == 0) && (len == strlen (optp->op))) { 159 if (w == 0) { 160 return (stringcomp(arg1, arg2, optp->opcode)); 161 } else { 162 return (arithcomp (arg1, arg2, optp->opcode, w)); 163 } 164 } 165 } 166 167 printf("Unknown operator '%s'\n", op); 168 return 0; /* op code not found */ 169 } 170 171 /* command line interface to the shell test */ 172 static int do_itest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 173 { 174 int value, w; 175 176 /* Validate arguments */ 177 if ((argc != 4)) 178 return CMD_RET_USAGE; 179 180 /* Check for a data width specification. 181 * Defaults to long (4) if no specification. 182 * Uses -2 as 'width' for .s (string) so as not to upset existing code 183 */ 184 switch (w = cmd_get_data_size(argv[0], 4)) { 185 case 1: 186 case 2: 187 case 4: 188 value = binary_test (argv[2], argv[1], argv[3], w); 189 break; 190 case -2: 191 value = binary_test (argv[2], argv[1], argv[3], 0); 192 break; 193 case -1: 194 default: 195 puts("Invalid data width specifier\n"); 196 value = 0; 197 break; 198 } 199 200 return !value; 201 } 202 203 U_BOOT_CMD( 204 itest, 4, 0, do_itest, 205 "return true/false on integer compare", 206 "[.b, .w, .l, .s] [*]value1 <op> [*]value2" 207 ); 208