blob: 23a404e008f72cc8499943991ff82fb9ed0bd1e2 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// 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 <flasher/convert.hpp>
#include <flasher/device/fake.hpp>
#include <stdplus/print.hpp>
#include <stdplus/raw.hpp>
#include <optional>
#include <utility>
#include <vector>
namespace flasher
{
namespace device
{
Fake::Fake(File& file, Type type, size_t erase) :
Device(buildDeviceInfo(file, type, erase)), file(&file),
erase_contents(erase)
{
mockErase(erase_contents);
}
std::span<std::byte> Fake::readAt(std::span<std::byte> buf, size_t offset)
{
return file->readAt(buf, offset);
}
std::span<const std::byte> Fake::writeAt(std::span<const std::byte> data,
size_t offset)
{
switch (info.type)
{
case Type::Nor:
{
std::vector<std::byte> out(data.size());
file->readAtExact(out, offset);
for (size_t i = 0; i < out.size(); ++i)
{
out[i] &= data[i];
}
file->writeAtExact(out, offset);
}
break;
case Type::Simple:
file->writeAtExact(data, offset);
break;
}
return data;
}
void Fake::eraseBlocks(size_t idx, size_t num)
{
for (size_t i = idx; i < idx + num; i++)
{
file->writeAtExact(stdplus::raw::asSpan<std::byte>(erase_contents),
i * erase_contents.size());
}
}
Device::DeviceInfo Fake::buildDeviceInfo(File& file, Type type, size_t erase)
{
DeviceInfo ret;
ret.type = type;
ret.erase_size = erase;
ret.size = file.getSize();
return ret;
}
FakeOwning::FakeOwning(std::unique_ptr<File>&& file, Type type, size_t erase) :
Fake(*file, type, erase), file(std::move(file))
{}
class FakeType : public DeviceType
{
public:
std::unique_ptr<Device> open(const ModArgs& args) override
{
if (args.arr.size() != 2)
{
throw std::invalid_argument("Requires a single file argument");
}
auto it = args.dict.find("type");
if (it == args.dict.end())
{
throw std::invalid_argument("Requires a type to be specified");
}
auto type = Device::toType(it->second);
it = args.dict.find("erase");
if (it == args.dict.end())
{
throw std::invalid_argument("Requires an erase to be specified");
}
auto erase = toUint32(it->second.c_str());
it = args.dict.find("size");
std::optional<size_t> size;
if (it != args.dict.end())
{
size = toUint32(it->second.c_str());
}
stdplus::fd::OpenFlags flags(stdplus::fd::OpenAccess::ReadWrite);
if (size)
{
flags.set(stdplus::fd::OpenFlag::Create);
}
ModArgs file_args(args.arr[1]);
auto file = openFile(file_args, flags);
if (size)
{
file->truncate(*size);
}
return std::make_unique<FakeOwning>(std::move(file), type, erase);
}
void printHelp() const override
{
stdplus::println(stderr, " `fake` device");
stdplus::println(stderr,
" type=TYPE required The type of flash "
"to use (nor, simple)");
stdplus::println(
stderr,
" erase=ERASE_SIZE required The erase size of the flash");
stdplus::println(stderr, " size=SIZE optional If specified, "
"truncates the file to SIZE");
stdplus::println(
stderr,
" FILE required Backing file specification");
}
};
void registerFake() __attribute__((constructor));
void registerFake()
{
registerDeviceType("fake", std::make_unique<FakeType>());
}
void unregisterFake() __attribute__((destructor));
void unregisterFake()
{
unregisterDeviceType("fake");
}
} // namespace device
} // namespace flasher