12e192b24SSimon Glass /* 22e192b24SSimon Glass * (C) Copyright 2003 32e192b24SSimon Glass * Tait Electronics Limited, Christchurch, New Zealand 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * This file provides a shell like 'test' function to return 102e192b24SSimon Glass * true/false from an integer or string compare of two memory 112e192b24SSimon Glass * locations or a location and a scalar/literal. 122e192b24SSimon Glass * A few parts were lifted from bash 'test' command 132e192b24SSimon Glass */ 142e192b24SSimon Glass 152e192b24SSimon Glass #include <common.h> 162e192b24SSimon Glass #include <config.h> 172e192b24SSimon Glass #include <command.h> 182e192b24SSimon Glass #include <mapmem.h> 192e192b24SSimon Glass 202e192b24SSimon Glass #include <asm/io.h> 212e192b24SSimon Glass 222e192b24SSimon Glass #define EQ 0 232e192b24SSimon Glass #define NE 1 242e192b24SSimon Glass #define LT 2 252e192b24SSimon Glass #define GT 3 262e192b24SSimon Glass #define LE 4 272e192b24SSimon Glass #define GE 5 282e192b24SSimon Glass 292e192b24SSimon Glass struct op_tbl_s { 302e192b24SSimon Glass char *op; /* operator string */ 312e192b24SSimon Glass int opcode; /* internal representation of opcode */ 322e192b24SSimon Glass }; 332e192b24SSimon Glass 342e192b24SSimon Glass typedef struct op_tbl_s op_tbl_t; 352e192b24SSimon Glass 362e192b24SSimon Glass static const op_tbl_t op_table [] = { 372e192b24SSimon Glass { "-lt", LT }, 382e192b24SSimon Glass { "<" , LT }, 392e192b24SSimon Glass { "-gt", GT }, 402e192b24SSimon Glass { ">" , GT }, 412e192b24SSimon Glass { "-eq", EQ }, 422e192b24SSimon Glass { "==" , EQ }, 432e192b24SSimon Glass { "-ne", NE }, 442e192b24SSimon Glass { "!=" , NE }, 452e192b24SSimon Glass { "<>" , NE }, 462e192b24SSimon Glass { "-ge", GE }, 472e192b24SSimon Glass { ">=" , GE }, 482e192b24SSimon Glass { "-le", LE }, 492e192b24SSimon Glass { "<=" , LE }, 502e192b24SSimon Glass }; 512e192b24SSimon Glass 522e192b24SSimon Glass static long evalexp(char *s, int w) 532e192b24SSimon Glass { 542e192b24SSimon Glass long l = 0; 552e192b24SSimon Glass unsigned long addr; 562e192b24SSimon Glass void *buf; 572e192b24SSimon Glass 582e192b24SSimon Glass /* if the parameter starts with a * then assume is a pointer to the value we want */ 592e192b24SSimon Glass if (s[0] == '*') { 602e192b24SSimon Glass addr = simple_strtoul(&s[1], NULL, 16); 612e192b24SSimon Glass buf = map_physmem(addr, w, MAP_WRBACK); 62986fe378SStephen Warren if (!buf && addr) { 632e192b24SSimon Glass puts("Failed to map physical memory\n"); 642e192b24SSimon Glass return 0; 652e192b24SSimon Glass } 662e192b24SSimon Glass switch (w) { 672e192b24SSimon Glass case 1: 68dafd6488SKunihiko Hayashi l = (long)(*(u8 *)buf); 692e192b24SSimon Glass break; 702e192b24SSimon Glass case 2: 71dafd6488SKunihiko Hayashi l = (long)(*(u16 *)buf); 722e192b24SSimon Glass break; 732e192b24SSimon Glass case 4: 74dafd6488SKunihiko Hayashi l = (long)(*(u32 *)buf); 752e192b24SSimon Glass break; 762e192b24SSimon Glass } 772e192b24SSimon Glass unmap_physmem(buf, w); 782e192b24SSimon Glass return l; 792e192b24SSimon Glass } else { 802e192b24SSimon Glass l = simple_strtoul(s, NULL, 16); 812e192b24SSimon Glass } 822e192b24SSimon Glass 83*2c79fd40SSebastien Colleur /* avoid overflow on mask calculus */ 84*2c79fd40SSebastien Colleur return (w >= sizeof(long)) ? l : (l & ((1UL << (w * 8)) - 1)); 852e192b24SSimon Glass } 862e192b24SSimon Glass 872e192b24SSimon Glass static char * evalstr(char *s) 882e192b24SSimon Glass { 892e192b24SSimon Glass /* if the parameter starts with a * then assume a string pointer else its a literal */ 902e192b24SSimon Glass if (s[0] == '*') { 912e192b24SSimon Glass return (char *)simple_strtoul(&s[1], NULL, 16); 922e192b24SSimon Glass } else if (s[0] == '$') { 932e192b24SSimon Glass int i = 2; 942e192b24SSimon Glass 952e192b24SSimon Glass if (s[1] != '{') 962e192b24SSimon Glass return NULL; 972e192b24SSimon Glass 982e192b24SSimon Glass while (s[i] != '}') { 992e192b24SSimon Glass if (s[i] == 0) 1002e192b24SSimon Glass return NULL; 1012e192b24SSimon Glass i++; 1022e192b24SSimon Glass } 1032e192b24SSimon Glass s[i] = 0; 1042e192b24SSimon Glass return getenv((const char *)&s[2]); 1052e192b24SSimon Glass } else { 1062e192b24SSimon Glass return s; 1072e192b24SSimon Glass } 1082e192b24SSimon Glass } 1092e192b24SSimon Glass 1102e192b24SSimon Glass static int stringcomp(char *s, char *t, int op) 1112e192b24SSimon Glass { 1122e192b24SSimon Glass int p; 1132e192b24SSimon Glass char *l, *r; 1142e192b24SSimon Glass 1152e192b24SSimon Glass l = evalstr(s); 1162e192b24SSimon Glass r = evalstr(t); 1172e192b24SSimon Glass 1182e192b24SSimon Glass p = strcmp(l, r); 1192e192b24SSimon Glass switch (op) { 1202e192b24SSimon Glass case EQ: return (p == 0); 1212e192b24SSimon Glass case NE: return (p != 0); 1222e192b24SSimon Glass case LT: return (p < 0); 1232e192b24SSimon Glass case GT: return (p > 0); 1242e192b24SSimon Glass case LE: return (p <= 0); 1252e192b24SSimon Glass case GE: return (p >= 0); 1262e192b24SSimon Glass } 1272e192b24SSimon Glass return (0); 1282e192b24SSimon Glass } 1292e192b24SSimon Glass 1302e192b24SSimon Glass static int arithcomp (char *s, char *t, int op, int w) 1312e192b24SSimon Glass { 1322e192b24SSimon Glass long l, r; 1332e192b24SSimon Glass 1342e192b24SSimon Glass l = evalexp (s, w); 1352e192b24SSimon Glass r = evalexp (t, w); 1362e192b24SSimon Glass 1372e192b24SSimon Glass switch (op) { 1382e192b24SSimon Glass case EQ: return (l == r); 1392e192b24SSimon Glass case NE: return (l != r); 1402e192b24SSimon Glass case LT: return (l < r); 1412e192b24SSimon Glass case GT: return (l > r); 1422e192b24SSimon Glass case LE: return (l <= r); 1432e192b24SSimon Glass case GE: return (l >= r); 1442e192b24SSimon Glass } 1452e192b24SSimon Glass return (0); 1462e192b24SSimon Glass } 1472e192b24SSimon Glass 1482e192b24SSimon Glass static int binary_test(char *op, char *arg1, char *arg2, int w) 1492e192b24SSimon Glass { 1502e192b24SSimon Glass int len, i; 1512e192b24SSimon Glass const op_tbl_t *optp; 1522e192b24SSimon Glass 1532e192b24SSimon Glass len = strlen(op); 1542e192b24SSimon Glass 1552e192b24SSimon Glass for (optp = (op_tbl_t *)&op_table, i = 0; 1562e192b24SSimon Glass i < ARRAY_SIZE(op_table); 1572e192b24SSimon Glass optp++, i++) { 1582e192b24SSimon Glass 1592e192b24SSimon Glass if ((strncmp (op, optp->op, len) == 0) && (len == strlen (optp->op))) { 1602e192b24SSimon Glass if (w == 0) { 1612e192b24SSimon Glass return (stringcomp(arg1, arg2, optp->opcode)); 1622e192b24SSimon Glass } else { 1632e192b24SSimon Glass return (arithcomp (arg1, arg2, optp->opcode, w)); 1642e192b24SSimon Glass } 1652e192b24SSimon Glass } 1662e192b24SSimon Glass } 1672e192b24SSimon Glass 1682e192b24SSimon Glass printf("Unknown operator '%s'\n", op); 1692e192b24SSimon Glass return 0; /* op code not found */ 1702e192b24SSimon Glass } 1712e192b24SSimon Glass 1722e192b24SSimon Glass /* command line interface to the shell test */ 1732e192b24SSimon Glass static int do_itest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 1742e192b24SSimon Glass { 1752e192b24SSimon Glass int value, w; 1762e192b24SSimon Glass 1772e192b24SSimon Glass /* Validate arguments */ 1782e192b24SSimon Glass if ((argc != 4)) 1792e192b24SSimon Glass return CMD_RET_USAGE; 1802e192b24SSimon Glass 1812e192b24SSimon Glass /* Check for a data width specification. 1822e192b24SSimon Glass * Defaults to long (4) if no specification. 1832e192b24SSimon Glass * Uses -2 as 'width' for .s (string) so as not to upset existing code 1842e192b24SSimon Glass */ 1852e192b24SSimon Glass switch (w = cmd_get_data_size(argv[0], 4)) { 1862e192b24SSimon Glass case 1: 1872e192b24SSimon Glass case 2: 1882e192b24SSimon Glass case 4: 1892e192b24SSimon Glass value = binary_test (argv[2], argv[1], argv[3], w); 1902e192b24SSimon Glass break; 1912e192b24SSimon Glass case -2: 1922e192b24SSimon Glass value = binary_test (argv[2], argv[1], argv[3], 0); 1932e192b24SSimon Glass break; 1942e192b24SSimon Glass case -1: 1952e192b24SSimon Glass default: 1962e192b24SSimon Glass puts("Invalid data width specifier\n"); 1972e192b24SSimon Glass value = 0; 1982e192b24SSimon Glass break; 1992e192b24SSimon Glass } 2002e192b24SSimon Glass 2012e192b24SSimon Glass return !value; 2022e192b24SSimon Glass } 2032e192b24SSimon Glass 2042e192b24SSimon Glass U_BOOT_CMD( 2052e192b24SSimon Glass itest, 4, 0, do_itest, 2062e192b24SSimon Glass "return true/false on integer compare", 2072e192b24SSimon Glass "[.b, .w, .l, .s] [*]value1 <op> [*]value2" 2082e192b24SSimon Glass ); 209