blob: d552b6a25470acd55cef18fb991f4039635c190a [file] [log] [blame]
Patrick Ventureaf696252018-12-11 10:22:14 -08001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "lpc.hpp"
18
Patrick Venture84778b82019-06-26 20:11:09 -070019#include "data.hpp"
20
Patrick Venture9b37b092020-05-28 20:58:57 -070021#include <ipmiblob/blob_errors.hpp>
22
Patrick Venture7c79b252019-06-24 16:06:21 -070023#include <cerrno>
Patrick Venture84778b82019-06-26 20:11:09 -070024#include <cstdint>
Patrick Venture8e1b2332019-01-17 15:22:45 -080025#include <cstring>
Patrick Venture84778b82019-06-26 20:11:09 -070026#include <memory>
27#include <string>
Patrick Venture8e1b2332019-01-17 15:22:45 -080028
Patrick Venture9b534f02018-12-13 16:10:02 -080029namespace host_tool
30{
31
Patrick Ventureaf696252018-12-11 10:22:14 -080032bool LpcDataHandler::sendContents(const std::string& input,
33 std::uint16_t session)
34{
Patrick Venture8e1b2332019-01-17 15:22:45 -080035 LpcRegion host_lpc_buf;
Patrick Venture03db87e2019-06-20 07:56:06 -070036 host_lpc_buf.address = address;
37 host_lpc_buf.length = length;
Patrick Venture8e1b2332019-01-17 15:22:45 -080038
39 std::vector<std::uint8_t> payload(sizeof(host_lpc_buf));
Patrick Venture8e1b2332019-01-17 15:22:45 -080040
Patrick Venture7c79b252019-06-24 16:06:21 -070041 while (true)
42 {
43 /* If the writeMeta() is rejected we need to call sessionStat on it. */
44 try
45 {
46 std::fprintf(stderr, "sending writeMeta\n");
Patrick Venture8e1b2332019-01-17 15:22:45 -080047
Patrick Venture7c79b252019-06-24 16:06:21 -070048 std::memcpy(payload.data(), &host_lpc_buf, sizeof(host_lpc_buf));
49 blob->writeMeta(session, 0x00, payload);
50
51 std::fprintf(stderr, "writemeta sent\n");
52
53 break;
54 }
55 catch (...)
56 {
57 std::fprintf(stderr, "caught exception\n");
58
59 ipmiblob::StatResponse resp = blob->getStat(session);
60 if (resp.metadata.empty())
61 {
62 std::fprintf(stderr, "Received no metadata bytes back!");
63 return false;
64 }
65
66 struct MemoryMapResultDetails
67 {
68 std::uint8_t code;
69 std::uint32_t offset;
70 std::uint32_t length;
71 } __attribute__((packed));
72
73 struct MemoryMapResultDetails bytes;
74
75 if (resp.metadata.size() != sizeof(bytes))
76 {
77 std::fprintf(
78 stderr,
79 "Received insufficient bytes back on expected return!\n");
80 return false;
81 }
82
83 std::memcpy(&bytes, resp.metadata.data(), sizeof(bytes));
84
85 if (bytes.code == EFBIG)
86 {
87 std::fprintf(stderr, "EFBIG returned!\n");
88
89 host_lpc_buf.length = bytes.length;
90 host_lpc_buf.address += bytes.offset;
91 }
92 else if (bytes.code == 0)
93 {
94 /* We're good, continue! */
95 break;
96 }
97 }
98 }
99
100 /* For data blockss, stage data, and send blob write command. */
101 int inputFd = sys->open(input.c_str(), 0);
102 if (inputFd < 0)
103 {
104 return false;
105 }
106
Patrick Venturecf9b2192019-06-27 12:09:52 -0700107 std::int64_t fileSize = sys->getSize(input.c_str());
108 if (fileSize == 0)
109 {
110 std::fprintf(stderr, "Zero-length file, or other file access error\n");
111 return false;
112 }
113
114 progress->start(fileSize);
115
Patrick Venture7c79b252019-06-24 16:06:21 -0700116 /* For Nuvoton the maximum is 4K */
117 auto readBuffer = std::make_unique<std::uint8_t[]>(host_lpc_buf.length);
118 if (nullptr == readBuffer)
119 {
William A. Kennington III0d5bb782021-01-19 15:50:42 -0800120 progress->abort();
Patrick Venture7c79b252019-06-24 16:06:21 -0700121 sys->close(inputFd);
122 std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
123 return false;
124 }
125
126 /* TODO: This is similar to PCI insomuch as how it sends data, so combine.
Patrick Venture8e1b2332019-01-17 15:22:45 -0800127 */
Patrick Venture7c79b252019-06-24 16:06:21 -0700128 try
129 {
130 int bytesRead = 0;
131 std::uint32_t offset = 0;
Patrick Venture8e1b2332019-01-17 15:22:45 -0800132
Patrick Venture7c79b252019-06-24 16:06:21 -0700133 do
134 {
135 bytesRead =
136 sys->read(inputFd, readBuffer.get(), host_lpc_buf.length);
137 if (bytesRead > 0)
138 {
139 if (!io->write(host_lpc_buf.address, bytesRead,
140 readBuffer.get()))
141 {
142 std::fprintf(stderr,
143 "Failed to write to region in memory!\n");
144 }
145
146 struct ipmi_flash::ExtChunkHdr chunk;
147 chunk.length = bytesRead;
148 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
149 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
150
151 /* This doesn't return anything on success. */
152 blob->writeBytes(session, offset, chunkBytes);
153 offset += bytesRead;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700154 progress->updateProgress(bytesRead);
Patrick Venture7c79b252019-06-24 16:06:21 -0700155 }
156 } while (bytesRead > 0);
157 }
158 catch (const ipmiblob::BlobException& b)
159 {
William A. Kennington III0d5bb782021-01-19 15:50:42 -0800160 progress->abort();
Patrick Venture7c79b252019-06-24 16:06:21 -0700161 sys->close(inputFd);
162 return false;
163 }
164
William A. Kennington III0d5bb782021-01-19 15:50:42 -0800165 progress->finish();
Patrick Venture7c79b252019-06-24 16:06:21 -0700166 sys->close(inputFd);
167 return true;
Patrick Ventureaf696252018-12-11 10:22:14 -0800168}
Patrick Venture9b534f02018-12-13 16:10:02 -0800169
170} // namespace host_tool