blob: 9359b92dfe066faba0743af1201000af39caa32e [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "lpc.hpp"
#include <cerrno>
#include <cstring>
#include <ipmiblob/blob_errors.hpp>
namespace host_tool
{
bool LpcDataHandler::sendContents(const std::string& input,
std::uint16_t session)
{
LpcRegion host_lpc_buf;
host_lpc_buf.address = address;
host_lpc_buf.length = length;
std::vector<std::uint8_t> payload(sizeof(host_lpc_buf));
while (true)
{
/* If the writeMeta() is rejected we need to call sessionStat on it. */
try
{
std::fprintf(stderr, "sending writeMeta\n");
std::memcpy(payload.data(), &host_lpc_buf, sizeof(host_lpc_buf));
blob->writeMeta(session, 0x00, payload);
std::fprintf(stderr, "writemeta sent\n");
break;
}
catch (...)
{
std::fprintf(stderr, "caught exception\n");
ipmiblob::StatResponse resp = blob->getStat(session);
if (resp.metadata.empty())
{
std::fprintf(stderr, "Received no metadata bytes back!");
return false;
}
struct MemoryMapResultDetails
{
std::uint8_t code;
std::uint32_t offset;
std::uint32_t length;
} __attribute__((packed));
struct MemoryMapResultDetails bytes;
if (resp.metadata.size() != sizeof(bytes))
{
std::fprintf(
stderr,
"Received insufficient bytes back on expected return!\n");
return false;
}
std::memcpy(&bytes, resp.metadata.data(), sizeof(bytes));
if (bytes.code == EFBIG)
{
std::fprintf(stderr, "EFBIG returned!\n");
host_lpc_buf.length = bytes.length;
host_lpc_buf.address += bytes.offset;
}
else if (bytes.code == 0)
{
/* We're good, continue! */
break;
}
}
}
/* For data blockss, stage data, and send blob write command. */
int inputFd = sys->open(input.c_str(), 0);
if (inputFd < 0)
{
return false;
}
/* For Nuvoton the maximum is 4K */
auto readBuffer = std::make_unique<std::uint8_t[]>(host_lpc_buf.length);
if (nullptr == readBuffer)
{
sys->close(inputFd);
std::fprintf(stderr, "Unable to allocate memory for read buffer.\n");
return false;
}
/* TODO: This is similar to PCI insomuch as how it sends data, so combine.
*/
try
{
int bytesRead = 0;
std::uint32_t offset = 0;
do
{
bytesRead =
sys->read(inputFd, readBuffer.get(), host_lpc_buf.length);
if (bytesRead > 0)
{
if (!io->write(host_lpc_buf.address, bytesRead,
readBuffer.get()))
{
std::fprintf(stderr,
"Failed to write to region in memory!\n");
}
struct ipmi_flash::ExtChunkHdr chunk;
chunk.length = bytesRead;
std::vector<std::uint8_t> chunkBytes(sizeof(chunk));
std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
/* This doesn't return anything on success. */
blob->writeBytes(session, offset, chunkBytes);
offset += bytesRead;
}
} while (bytesRead > 0);
}
catch (const ipmiblob::BlobException& b)
{
sys->close(inputFd);
return false;
}
sys->close(inputFd);
return true;
}
} // namespace host_tool