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