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