blob: db9e892e6a50964385e9e83a4f271b77dbbdab86 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
Miguel Young de la Sota3fbb28a2019-10-16 15:15:07 -05005#include "sw/host/spiflash/verilator_spi_interface.h"
lowRISC Contributors802543a2019-08-31 12:12:56 +01006
lowRISC Contributors802543a2019-08-31 12:12:56 +01007#include <cstring>
Miguel Osorio4359ef32021-05-25 20:56:01 -07008#include <fcntl.h>
lowRISC Contributors802543a2019-08-31 12:12:56 +01009#include <iostream>
10#include <string>
Miguel Osorio4359ef32021-05-25 20:56:01 -070011#include <termios.h>
12#include <unistd.h>
Jon Flatleyed09deb2020-02-26 16:18:47 -050013#include <vector>
lowRISC Contributors802543a2019-08-31 12:12:56 +010014
Miguel Osorio4359ef32021-05-25 20:56:01 -070015#include "cryptoc/sha256.h"
16
lowRISC Contributors802543a2019-08-31 12:12:56 +010017namespace opentitan {
18namespace spiflash {
19namespace {
20
lowRISC Contributors802543a2019-08-31 12:12:56 +010021// TODO: If transmission is not successful, adapt this by an argument.
Miguel Osoriodbc6e272020-06-28 17:53:31 -070022/** Required delay to synchronize transactions with simulation environment. */
lowRISC Contributors802543a2019-08-31 12:12:56 +010023constexpr int kWriteReadDelay = 20000000;
24
Miguel Osoriodbc6e272020-06-28 17:53:31 -070025/** Configure `fd` as a serial port with baud rate 9600. */
lowRISC Contributors802543a2019-08-31 12:12:56 +010026bool SetTermOpts(int fd) {
27 struct termios options;
28 if (tcgetattr(fd, &options) != 0) {
29 return false;
30 }
31 cfmakeraw(&options);
32 // The current Verilator configuration uses 9600 baud rate.
33 if (cfsetispeed(&options, B9600) != 0) {
34 return false;
35 }
36 if (cfsetospeed(&options, B9600) != 0) {
37 return false;
38 }
39 if (tcsetattr(fd, TCSANOW, &options) != 0) {
40 return false;
41 }
42 return true;
43}
44
Miguel Osoriodbc6e272020-06-28 17:53:31 -070045/**
46 * Returns file handle on success, or -1 on failure. This function
47 * configures de file handle to behave as a serial port with baud rate 9600,
48 * which is the baud rate supported by Verilator.
49 */
lowRISC Contributors802543a2019-08-31 12:12:56 +010050int OpenDevice(const std::string &filename) {
51 int fd = open(filename.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
52 if (fd < 0) {
53 std::cerr << "Failed to open device: " << filename << std::endl;
54 return fd;
55 }
56 if (!SetTermOpts(fd)) {
57 close(fd);
58 return -1;
59 }
60 return fd;
61}
62
Miguel Osoriodbc6e272020-06-28 17:53:31 -070063/**
64 * Reads `size` bytes into `rx` buffer from `fd`. Returns the number of bytes
65 * read.
66 */
Jon Flatleyed09deb2020-02-26 16:18:47 -050067size_t ReadBytes(int fd, uint8_t *rx, size_t size) {
lowRISC Contributors802543a2019-08-31 12:12:56 +010068 size_t bytes_read = 0;
69 while (bytes_read != size) {
Jon Flatleyed09deb2020-02-26 16:18:47 -050070 ssize_t read_size = read(fd, &rx[bytes_read], size - bytes_read);
lowRISC Contributors802543a2019-08-31 12:12:56 +010071 switch (read_size) {
72 case -1:
73 if (errno == EAGAIN || errno == EWOULDBLOCK) {
74 continue;
75 }
76 break;
77 default:
78 bytes_read += read_size;
79 }
80 }
81 return bytes_read;
82}
83
84} // namespace
85
86VerilatorSpiInterface::~VerilatorSpiInterface() {
87 if (fd_ != -1) {
88 close(fd_);
89 }
90}
91
92bool VerilatorSpiInterface::Init() {
93 fd_ = OpenDevice(spi_filename_);
94 if (fd_ < 0) {
95 return false;
96 }
97 return true;
98}
99
Jon Flatleyed09deb2020-02-26 16:18:47 -0500100bool VerilatorSpiInterface::TransmitFrame(const uint8_t *tx, size_t size) {
lowRISC Contributors802543a2019-08-31 12:12:56 +0100101 size_t bytes_written = write(fd_, tx, size);
102 if (bytes_written != size) {
103 std::cerr << "Failed to write bytes to spi interface. Bytes written: "
104 << bytes_written << " expected: " << size << std::endl;
105 return false;
106 }
107 usleep(kWriteReadDelay);
Jon Flatleyed09deb2020-02-26 16:18:47 -0500108 return true;
109}
110
111bool VerilatorSpiInterface::CheckHash(const uint8_t *tx, size_t size) {
Miguel Osorio4359ef32021-05-25 20:56:01 -0700112 uint8_t hash[SHA256_DIGEST_SIZE];
113 SHA256_hash(tx, size, hash);
Jon Flatleyed09deb2020-02-26 16:18:47 -0500114
115 std::vector<uint8_t> rx(size);
116 size_t bytes_read = ReadBytes(fd_, &rx[0], size);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100117 if (bytes_read < size) {
118 std::cerr << "Failed to read bytes from spi interface. Bytes read: "
119 << bytes_read << " expected: " << size << std::endl;
120 }
Jon Flatleyed09deb2020-02-26 16:18:47 -0500121
Miguel Osorio4359ef32021-05-25 20:56:01 -0700122 return !std::memcmp(&rx[0], hash, SHA256_DIGEST_SIZE);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100123}
124} // namespace spiflash
125} // namespace opentitan