blob: 36160854118ff5f33f18c38092a4880ae44b0237 [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 Venture7c79b252019-06-24 16:06:21 -070021#include <cerrno>
Patrick Venture84778b82019-06-26 20:11:09 -070022#include <cstdint>
Patrick Venture8e1b2332019-01-17 15:22:45 -080023#include <cstring>
Patrick Venture7c79b252019-06-24 16:06:21 -070024#include <ipmiblob/blob_errors.hpp>
Patrick Venture84778b82019-06-26 20:11:09 -070025#include <memory>
26#include <string>
Patrick Venture8e1b2332019-01-17 15:22:45 -080027
Patrick Venture9b534f02018-12-13 16:10:02 -080028namespace host_tool
29{
30
Patrick Ventureaf696252018-12-11 10:22:14 -080031bool LpcDataHandler::sendContents(const std::string& input,
32 std::uint16_t session)
33{
Patrick Venture8e1b2332019-01-17 15:22:45 -080034 LpcRegion host_lpc_buf;
Patrick Venture03db87e2019-06-20 07:56:06 -070035 host_lpc_buf.address = address;
36 host_lpc_buf.length = length;
Patrick Venture8e1b2332019-01-17 15:22:45 -080037
38 std::vector<std::uint8_t> payload(sizeof(host_lpc_buf));
Patrick Venture8e1b2332019-01-17 15:22:45 -080039
Patrick Venture7c79b252019-06-24 16:06:21 -070040 while (true)
41 {
42 /* If the writeMeta() is rejected we need to call sessionStat on it. */
43 try
44 {
45 std::fprintf(stderr, "sending writeMeta\n");
Patrick Venture8e1b2332019-01-17 15:22:45 -080046
Patrick Venture7c79b252019-06-24 16:06:21 -070047 std::memcpy(payload.data(), &host_lpc_buf, sizeof(host_lpc_buf));
48 blob->writeMeta(session, 0x00, payload);
49
50 std::fprintf(stderr, "writemeta sent\n");
51
52 break;
53 }
54 catch (...)
55 {
56 std::fprintf(stderr, "caught exception\n");
57
58 ipmiblob::StatResponse resp = blob->getStat(session);
59 if (resp.metadata.empty())
60 {
61 std::fprintf(stderr, "Received no metadata bytes back!");
62 return false;
63 }
64
65 struct MemoryMapResultDetails
66 {
67 std::uint8_t code;
68 std::uint32_t offset;
69 std::uint32_t length;
70 } __attribute__((packed));
71
72 struct MemoryMapResultDetails bytes;
73
74 if (resp.metadata.size() != sizeof(bytes))
75 {
76 std::fprintf(
77 stderr,
78 "Received insufficient bytes back on expected return!\n");
79 return false;
80 }
81
82 std::memcpy(&bytes, resp.metadata.data(), sizeof(bytes));
83
84 if (bytes.code == EFBIG)
85 {
86 std::fprintf(stderr, "EFBIG returned!\n");
87
88 host_lpc_buf.length = bytes.length;
89 host_lpc_buf.address += bytes.offset;
90 }
91 else if (bytes.code == 0)
92 {
93 /* We're good, continue! */
94 break;
95 }
96 }
97 }
98
99 /* For data blockss, stage data, and send blob write command. */
100 int inputFd = sys->open(input.c_str(), 0);
101 if (inputFd < 0)
102 {
103 return false;
104 }
105
Patrick Venturecf9b2192019-06-27 12:09:52 -0700106 std::int64_t fileSize = sys->getSize(input.c_str());
107 if (fileSize == 0)
108 {
109 std::fprintf(stderr, "Zero-length file, or other file access error\n");
110 return false;
111 }
112
113 progress->start(fileSize);
114
Patrick Venture7c79b252019-06-24 16:06:21 -0700115 /* For Nuvoton the maximum is 4K */
116 auto readBuffer = std::make_unique<std::uint8_t[]>(host_lpc_buf.length);
117 if (nullptr == readBuffer)
118 {
119 sys->close(inputFd);
120 std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
121 return false;
122 }
123
124 /* TODO: This is similar to PCI insomuch as how it sends data, so combine.
Patrick Venture8e1b2332019-01-17 15:22:45 -0800125 */
Patrick Venture7c79b252019-06-24 16:06:21 -0700126 try
127 {
128 int bytesRead = 0;
129 std::uint32_t offset = 0;
Patrick Venture8e1b2332019-01-17 15:22:45 -0800130
Patrick Venture7c79b252019-06-24 16:06:21 -0700131 do
132 {
133 bytesRead =
134 sys->read(inputFd, readBuffer.get(), host_lpc_buf.length);
135 if (bytesRead > 0)
136 {
137 if (!io->write(host_lpc_buf.address, bytesRead,
138 readBuffer.get()))
139 {
140 std::fprintf(stderr,
141 "Failed to write to region in memory!\n");
142 }
143
144 struct ipmi_flash::ExtChunkHdr chunk;
145 chunk.length = bytesRead;
146 std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
147 std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
148
149 /* This doesn't return anything on success. */
150 blob->writeBytes(session, offset, chunkBytes);
151 offset += bytesRead;
Patrick Venturecf9b2192019-06-27 12:09:52 -0700152 progress->updateProgress(bytesRead);
Patrick Venture7c79b252019-06-24 16:06:21 -0700153 }
154 } while (bytesRead > 0);
155 }
156 catch (const ipmiblob::BlobException& b)
157 {
158 sys->close(inputFd);
159 return false;
160 }
161
162 sys->close(inputFd);
163 return true;
Patrick Ventureaf696252018-12-11 10:22:14 -0800164}
Patrick Venture9b534f02018-12-13 16:10:02 -0800165
166} // namespace host_tool