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
evalexp(char * s,int w)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
832c79fd40SSebastien Colleur /* avoid overflow on mask calculus */
842c79fd40SSebastien Colleur return (w >= sizeof(long)) ? l : (l & ((1UL << (w * 8)) - 1));
852e192b24SSimon Glass }
862e192b24SSimon Glass
evalstr(char * s)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;
104*00caae6dSSimon Glass return env_get((const char *)&s[2]);
1052e192b24SSimon Glass } else {
1062e192b24SSimon Glass return s;
1072e192b24SSimon Glass }
1082e192b24SSimon Glass }
1092e192b24SSimon Glass
stringcomp(char * s,char * t,int op)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
arithcomp(char * s,char * t,int op,int w)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
binary_test(char * op,char * arg1,char * arg2,int w)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 */
do_itest(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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