blob: 70b9fe5b1a80239d9c36b4d6b54ff2cabf9c2260 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BIOD_CROS_FP_DEVICE_H_
#define BIOD_CROS_FP_DEVICE_H_
#include <sys/ioctl.h>
#include <bitset>
#include <memory>
#include <string>
#include <vector>
#include <base/files/file_util.h>
#include <base/message_loop/message_loop.h>
#include <chromeos/ec/cros_ec_dev.h>
#include <chromeos/ec/ec_commands.h>
#include "biod/uinput_device.h"
using MessageLoopForIO = base::MessageLoopForIO;
using VendorTemplate = std::vector<uint8_t>;
namespace biod {
class CrosFpDevice : public MessageLoopForIO::Watcher {
public:
using MkbpCallback = base::Callback<void(const uint32_t event)>;
explicit CrosFpDevice(const MkbpCallback& mkbp_event)
: mkbp_event_(mkbp_event),
fd_watcher_(std::make_unique<MessageLoopForIO::FileDescriptorWatcher>(
FROM_HERE)) {}
~CrosFpDevice();
static std::unique_ptr<CrosFpDevice> Open(const MkbpCallback& callback);
// Run a simple command to get the version information from FP MCU and check
// whether the image type returned is the same as |expected_image|.
static bool WaitOnEcBoot(const base::ScopedFD& cros_fp_fd,
ec_current_image expected_image);
bool FpMode(uint32_t mode);
bool GetFpMode(uint32_t* mode);
bool GetFpStats(int* capture_ms, int* matcher_ms, int* overall_ms);
bool GetDirtyMap(std::bitset<32>* bitmap);
bool GetTemplate(int index, VendorTemplate* out);
bool UploadTemplate(const VendorTemplate& tmpl);
bool SetContext(std::string user_id);
bool ResetContext();
// Initialise the entropy in the SBP. If |reset| is true, the old entropy
// will be deleted. If |reset| is false, we will only add entropy, and only
// if no entropy had been added before.
bool InitEntropy(bool reset = false);
int MaxTemplateCount() { return info_.template_max; }
int TemplateVersion() { return info_.template_version; }
// Kernel device exposing the MCU command interface.
static constexpr char kCrosFpPath[] = "/dev/cros_fp";
static constexpr int kLastTemplate = -1;
protected:
// MessageLoopForIO::Watcher overrides:
void OnFileCanReadWithoutBlocking(int fd) override;
void OnFileCanWriteWithoutBlocking(int fd) override {}
private:
bool Init();
bool EcDevInit();
bool EcProtoInfo(ssize_t* max_read, ssize_t* max_write);
bool EcReboot(ec_current_image to_image);
// Run the EC command to generate new entropy in the underlying MCU.
// |reset| specifies whether we want to merely add entropy (false), or
// perform a reset, which erases old entropy(true).
bool AddEntropy(bool reset);
// Get block id from rollback info.
bool GetRollBackInfoId(int32_t* block_id);
bool SetUpFp();
bool FpFrame(int index, std::vector<uint8_t>* frame);
bool UpdateFpInfo();
// Run a sequence of EC commands to update the entropy in the
// MCU. If |reset| is set to true, it will additionally erase the existing
// entropy too.
bool UpdateEntropy(bool reset);
base::ScopedFD cros_fd_;
ssize_t max_read_size_;
ssize_t max_write_size_;
struct ec_response_fp_info info_;
MkbpCallback mkbp_event_;
UinputDevice input_device_;
std::unique_ptr<MessageLoopForIO::FileDescriptorWatcher> fd_watcher_;
DISALLOW_COPY_AND_ASSIGN(CrosFpDevice);
};
// Empty request or response for the EcCommand template below.
struct EmptyParam {};
// empty struct is one byte in C++, get the size we want instead.
template <typename T>
constexpr size_t realsizeof() {
return std::is_empty<T>::value ? 0 : sizeof(T);
}
// Helper to build and send the command structures for cros_fp.
template <typename O, typename I>
class EcCommand {
public:
explicit EcCommand(uint32_t cmd, uint32_t ver = 0, const O& req = {})
: data_({
.cmd = {.version = ver,
.command = cmd,
.result = 0xff,
.outsize = realsizeof<O>(),
.insize = realsizeof<I>()},
.req = req,
}) {}
void SetRespSize(uint32_t insize) { data_.cmd.insize = insize; }
void SetReqSize(uint32_t outsize) { data_.cmd.outsize = outsize; }
void SetReq(const O& req) { data_.req = req; }
bool Run(int ec_fd) {
data_.cmd.result = 0xff;
int result = ioctl(ec_fd, CROS_EC_DEV_IOCXCMD_V2, &data_);
if (result < 0) {
PLOG(ERROR) << "FPMCU ioctl failed, command: " << data_.cmd.command;
return false;
}
return (static_cast<uint32_t>(result) == data_.cmd.insize);
}
I* Resp() { return &data_.resp; }
O* Req() { return &data_.req; }
uint16_t Result() { return data_.cmd.result; }
private:
struct {
struct cros_ec_command_v2 cmd;
union {
O req;
I resp;
};
} data_;
DISALLOW_COPY_AND_ASSIGN(EcCommand);
};
} // namespace biod
#endif // BIOD_CROS_FP_DEVICE_H_