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