aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2014-09-03 17:57:37 -0400
committerPaul Selkirk <paul@psgd.org>2014-09-03 17:57:37 -0400
commit6ff743f2abb05b07bd3c5585f59b14c459c69bfa (patch)
treecb5c887b2fbfcf7a0fc844451cffd3c04470018d
parentf06583ef515bae8f24d696e0df75a425bc47c2bb (diff)
hash_tester should read the correct number of response bytes
Both versions of hash_tester optimistically assumed a READ_OK or WRITE_OK response, and tried to read the expected number of bytes. But ERROR and UNKNOWN responses are shorter, which could lead to an overrun of available data from i2c. With commit a768072, this is no longer fatal (i2c will zero-pad the response), but it's good form to do the right thing when possible.
-rw-r--r--src/sw/hash_tester.c89
-rwxr-xr-xsrc/sw/hash_tester.py76
2 files changed, 114 insertions, 51 deletions
diff --git a/src/sw/hash_tester.c b/src/sw/hash_tester.c
index d02db41..f202a03 100644
--- a/src/sw/hash_tester.c
+++ b/src/sw/hash_tester.c
@@ -63,15 +63,16 @@
#define EOC 0xaa
#define READ_CMD 0x10
#define WRITE_CMD 0x11
+#define RESET_CMD 0x01
/* response codes */
#define SOR 0xaa
#define EOR 0x55
-#define UNKNOWN 0xfe
-#define ERROR 0xfd
#define READ_OK 0x7f
#define WRITE_OK 0x7e
#define RESET_OK 0x7d
+#define UNKNOWN 0xfe
+#define ERROR 0xfd
/* addresses and codes common to all hash cores */
#define ADDR_NAME0 0x00
@@ -253,26 +254,16 @@ int i2c_write(uint8_t *buf, int len)
return 0;
}
-int i2c_read(uint8_t *buf, int len)
+int i2c_read(uint8_t *b)
{
- int i;
-
- if (debug)
- printf("read [");
-
- for (i = 0; i < len; ++i) {
- if (read(i2cfd, &buf[i], 1) != 1) {
- fprintf(stderr, "i2c read failed on byte %d: ", i);
- perror("");
- return 1;
- }
- if (debug)
- printf(" %02x", buf[i]);
+ /* read() on the i2c device only returns one byte at a time,
+ * and tc_get_resp() needs to parse the response one byte at a time
+ */
+ if (read(i2cfd, b, 1) != 1) {
+ perror("i2c read failed");
+ return 1;
}
- if (debug)
- printf(" ]\n");
-
return 0;
}
@@ -307,12 +298,58 @@ int tc_send_read_cmd(uint8_t addr0, uint8_t addr1)
return i2c_write(buf, sizeof(buf));
}
-int tc_get_resp(uint8_t *expected, int len)
+int tc_get_resp(uint8_t *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; ++i) {
+ if (i2c_read(&buf[i]) != 0)
+ return 1;
+ if ((i == 0) && (buf[i] != SOR)) {
+ /* we've gotten out of sync, and there's probably nothing we can do */
+ fprintf(stderr, "response byte 0: expected 0x%02x (SOR), got 0x%02x\n",
+ SOR, buf[0]);
+ return 1;
+ }
+ else if (i == 1) { /* response code */
+ switch (buf[i]) {
+ case READ_OK:
+ len = 9;
+ break;
+ case WRITE_OK:
+ len = 5;
+ break;
+ case RESET_OK:
+ len = 3;
+ break;
+ case ERROR:
+ case UNKNOWN:
+ len = 4;
+ break;
+ default:
+ /* we've gotten out of sync, and there's probably nothing we can do */
+ fprintf(stderr, "unknown response code 0x%02x\n", buf[i]);
+ return 1;
+ }
+ }
+ }
+
+ if (debug) {
+ printf("read [");
+ for (i = 0; i < len; ++i)
+ printf(" %02x", buf[i]);
+ printf(" ]\n");
+ }
+
+ return 0;
+}
+
+int tc_get_expected(uint8_t *expected, int len)
{
uint8_t buf[9];
int i;
- if (i2c_read(buf, len) != 0)
+ if (tc_get_resp(buf, sizeof(buf)) != 0)
return 1;
for (i = 0; i < len; ++i) {
@@ -336,7 +373,7 @@ int tc_get_write_resp(uint8_t addr0, uint8_t addr1)
expected[3] = addr1;
expected[4] = EOR;
- return tc_get_resp(expected, sizeof(expected));
+ return tc_get_expected(expected, sizeof(expected));
}
int tc_get_read_resp(uint8_t addr0, uint8_t addr1, uint32_t data)
@@ -353,7 +390,7 @@ int tc_get_read_resp(uint8_t addr0, uint8_t addr1, uint32_t data)
expected[7] = data & 0xff;
expected[8] = EOR;
- return tc_get_resp(expected, sizeof(expected));
+ return tc_get_expected(expected, sizeof(expected));
}
int tc_write(uint8_t addr0, uint8_t addr1, uint32_t data)
@@ -385,7 +422,9 @@ int tc_wait(uint8_t addr0, uint8_t status)
do {
if (tc_send_read_cmd(addr0, ADDR_STATUS) != 0)
return 1;
- if (i2c_read(buf, 9) != 0)
+ if (tc_get_resp(buf, 9) != 0)
+ return 1;
+ if (buf[1] != READ_OK)
return 1;
} while ((buf[7] & status) != status);
@@ -869,7 +908,7 @@ int main(int argc, char *argv[])
int addr = I2C_addr;
int i, j, opt;
- while ((opt = getopt(argc, argv, "di:a:")) != -1) {
+ while ((opt = getopt(argc, argv, "h?di:a:")) != -1) {
switch (opt) {
case 'h':
case '?':
diff --git a/src/sw/hash_tester.py b/src/sw/hash_tester.py
index e2b3777..6a5ff0b 100755
--- a/src/sw/hash_tester.py
+++ b/src/sw/hash_tester.py
@@ -158,9 +158,6 @@ SHA512_DOUBLE_DIGEST = [ 0x8e959b75, 0xdae313da, 0x8cf4f728, 0x14fc143f,
0x501d289e, 0x4900f7e4, 0x331b99de, 0xc4b5433a,
0xc7d329ee, 0xb6dd2654, 0x5e96e55b, 0x874be909 ]
-def hexlist(list):
- return "[ " + ' '.join('%02x' % b for b in list) + " ]"
-
#----------------------------------------------------------------
# I2C class
#----------------------------------------------------------------
@@ -172,6 +169,9 @@ I2C_addr = 0x0f
# from /usr/include/linux/i2c-dev.h
I2C_SLAVE = 0x0703
+def hexlist(list):
+ return "[ " + ' '.join('%02x' % b for b in list) + " ]"
+
class I2C:
# file handle for the i2c device
file = None
@@ -202,15 +202,11 @@ class I2C:
print "write %s" % hexlist(buf)
self.file.write(bytearray(buf))
- # read 5 or 9 response bytes to a buffer
- def read(self, len):
- buf = []
- # read() on the i2c device will only return 1 byte at a time
- for i in range(len):
- buf.append(ord(self.file.read(1)))
- if DEBUG:
- print "read %s" % hexlist(buf)
- return buf
+ # read one response byte from the i2c device
+ def read(self):
+ # read() on the i2c device will only return one byte at a time,
+ # and tc.get_resp() needs to parse the response one byte at a time
+ return ord(self.file.read(1))
#----------------------------------------------------------------
# test-case class
@@ -221,12 +217,16 @@ SOC = 0x55
EOC = 0xaa
READ_CMD = 0x10
WRITE_CMD = 0x11
+RESET_CMD = 0x01
# response codes
SOR = 0xaa
EOR = 0x55
READ_OK = 0x7f
WRITE_OK = 0x7e
+RESET_OK = 0x7d
+UNKNOWN = 0xfe
+ERROR = 0xfd
class TcError(Exception):
pass
@@ -248,22 +248,46 @@ class tc:
buf = [SOC, READ_CMD, self.addr0, self.addr1, EOC]
self.i2c.write(buf)
- def get_resp(self, expected):
- buf = self.i2c.read(len(expected))
+ def get_resp(self):
+ buf = []
+ len = 2
+ i = 0
+ while i < len:
+ b = self.i2c.read()
+ if ((i == 0) and (b != SOR)):
+ # we've gotten out of sync, and there's probably nothing we can do
+ print "response byte 0: expected 0x%02x (SOR), got 0x%02x" % (SOR, b)
+ raise TcError()
+ elif (i == 1): # response code
+ try:
+ # anonymous dictionary of message lengths
+ len = {READ_OK:9, WRITE_OK:5, RESET_OK:3, ERROR:4, UNKNOWN:4}[b]
+ except KeyError: # unknown response code
+ # we've gotten out of sync, and there's probably nothing we can do
+ print "unknown response code 0x%02x" % b
+ raise TcError()
+ buf.append(b)
+ i += 1
+ if DEBUG:
+ print "read %s" % hexlist(buf)
+ return buf
+
+ def get_expected(self, expected):
+ buf = self.get_resp()
if (buf != expected):
print "expected %s,\nreceived %s" % (hexlist(expected), hexlist(buf))
raise TcError()
def get_write_resp(self):
expected = [SOR, WRITE_OK, self.addr0, self.addr1, EOR]
- self.get_resp(expected)
+ self.get_expected(expected)
def get_read_resp(self, data):
expected = [SOR, READ_OK, self.addr0, self.addr1]
for s in (24, 16, 8, 0):
expected.append(data >> s & 0xff)
expected.append(EOR)
- self.get_resp(expected)
+ self.get_expected(expected)
def write(self, data):
self.send_write_cmd(data)
@@ -289,7 +313,7 @@ def tc_wait(i2c, addr0, status):
t = tc(i2c, addr0, ADDR_STATUS)
while 1:
t.send_read_cmd()
- buf = t.i2c.read(9)
+ buf = t.get_resp()
if ((buf[7] & status) == status):
break
@@ -328,9 +352,9 @@ def sha1_wait_valid(i2c):
def TC1(i2c):
print "TC1: Reading name, type and version words from SHA-1 core."
- sha1_read(i2c, ADDR_NAME0, 0x73686131) # "sha1"
- sha1_read(i2c, ADDR_NAME1, 0x20202020) # " "
- sha1_read(i2c, ADDR_VERSION, 0x302e3530) # "0.50"
+ sha1_read(i2c, ADDR_NAME0, 0x73686131) # "sha1"
+ sha1_read(i2c, ADDR_NAME1, 0x20202020) # " "
+ sha1_read(i2c, ADDR_VERSION, 0x302e3530) # "0.50"
# TC2: SHA-1 Single block message test as specified by NIST.
def TC2(i2c):
@@ -413,9 +437,9 @@ def sha256_wait_valid(i2c):
def TC4(i2c):
print "TC4: Reading name, type and version words from SHA-256 core."
- sha256_read(i2c, ADDR_NAME0, 0x73686132) # "sha2"
- sha256_read(i2c, ADDR_NAME1, 0x2d323536) # "-256"
- sha256_read(i2c, ADDR_VERSION, 0x302e3830) # "0.80"
+ sha256_read(i2c, ADDR_NAME0, 0x73686132) # "sha2"
+ sha256_read(i2c, ADDR_NAME1, 0x2d323536) # "-256"
+ sha256_read(i2c, ADDR_VERSION, 0x302e3830) # "0.80"
# TC5: SHA-256 Single block message test as specified by NIST.
def TC5(i2c):
@@ -539,9 +563,9 @@ def sha512_wait_valid(i2c):
def TC8(i2c):
print "TC8: Reading name, type and version words from SHA-512 core."
- sha512_read(i2c, ADDR_NAME0, 0x73686132) # "sha2"
- sha512_read(i2c, ADDR_NAME1, 0x2d353132) # "-512"
- sha512_read(i2c, ADDR_VERSION, 0x302e3830) # "0.80"
+ sha512_read(i2c, ADDR_NAME0, 0x73686132) # "sha2"
+ sha512_read(i2c, ADDR_NAME1, 0x2d353132) # "-512"
+ sha512_read(i2c, ADDR_VERSION, 0x302e3830) # "0.80"
# TC9: SHA-512 Single block message test as specified by NIST.
# We do this for all modes.