-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcros_fp_firmware.cc
164 lines (138 loc) · 4.97 KB
/
cros_fp_firmware.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2019 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.
#include "biod/cros_fp_firmware.h"
#include <string>
#include <base/logging.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/memory_mapped_file.h>
#include <chromeos/ec/ec_commands.h>
#include <fmap.h>
namespace {
constexpr char kFmapRoIdLabel[] = "RO_FRID";
constexpr char kFmapRwIdLabel[] = "RW_FWID";
bool DecodeVersionFromArea(const base::MemoryMappedFile& image,
const struct fmap* fmap,
const char* area_name,
std::string* ver) {
DCHECK(fmap != nullptr);
DCHECK(area_name != nullptr);
DCHECK(ver != nullptr);
const auto area = fmap_find_area(fmap, area_name);
if (area == nullptr) {
LOG(ERROR) << "Failed to find FMAP area " << area_name << ".";
return false;
}
if ((area->offset + area->size) > fmap->size) {
LOG(ERROR) << "FMAP area " << area_name << " has offset " << area->offset
<< " with size " << area->size
<< ", which spans outside the firmware image, of size "
<< fmap->size << ".";
return false;
}
// area->size can be larger than the printable characters in the buffer
// std::string(char*, size_t) constructor will not stop at first \0
const char* str =
reinterpret_cast<const char*>(&(image.data()[area->offset]));
*ver = std::string(str, strnlen(str, area->size));
return true;
}
} // namespace
namespace biod {
CrosFpFirmware::CrosFpFirmware(const base::FilePath& image_path)
: path_(image_path) {
DecodeVersionFromFile();
}
base::FilePath CrosFpFirmware::GetPath() const {
return path_;
}
bool CrosFpFirmware::IsValid() const {
return status_ == Status::kOk;
}
CrosFpFirmware::Status CrosFpFirmware::GetStatus() const {
return status_;
}
std::string CrosFpFirmware::GetStatusString() const {
return StatusToString(GetStatus());
}
const CrosFpFirmware::ImageVersion& CrosFpFirmware::GetVersion() const {
return version_;
}
std::string CrosFpFirmware::StatusToString(Status status) {
switch (status) {
case CrosFpFirmware::Status::kUninitialized:
return "Not initialized";
case CrosFpFirmware::Status::kNotFound:
return "Firmware file does not exist.";
case CrosFpFirmware::Status::kBadFmap:
return "Firmware file has bad FMAP.";
case CrosFpFirmware::Status::kOpenError:
return "Failed to open firmware file version.";
case CrosFpFirmware::Status::kOk:
return "Firmware file is okay.";
}
NOTREACHED();
return "";
}
void CrosFpFirmware::DecodeVersionFromFile() {
if (!base::PathExists(path_) || base::DirectoryExists(path_)) {
LOG(ERROR) << "Failed to find firmware file '" << path_.value() << "'.";
status_ = Status::kNotFound;
return;
}
base::MemoryMappedFile image;
if (!image.Initialize(path_) || !image.IsValid()) {
PLOG(ERROR) << "Failed to open firmware file '" << path_.value() << "'.";
status_ = Status::kOpenError;
return;
}
auto fmap_offset = fmap_find(image.data(), image.length());
if (fmap_offset < 0 || fmap_offset >= image.length()) {
LOG(ERROR) << "Failed to find FMAP inside firmware file '" << path_.value()
<< "'.";
status_ = Status::kBadFmap;
return;
}
DLOG(INFO) << "FMAP signature found at offset " << fmap_offset << ".";
base::MemoryMappedFile image_fmap_aligned;
const base::MemoryMappedFile::Region image_fmap_aligned_region = {
.offset = fmap_offset,
.size = image.length() - fmap_offset,
};
// MemoryMappedFile doesn't allow sharing the same open file with another
// MemoryMappedFile nor does it allow mapping multiple file regions,
// so we need to open the same file again.
if (!image_fmap_aligned.Initialize(
base::File(path_, base::File::FLAG_OPEN | base::File::FLAG_READ),
image_fmap_aligned_region) ||
!image_fmap_aligned.IsValid()) {
PLOG(ERROR) << "Failed to open firmware file's fmap region '"
<< path_.value() << "'.";
status_ = Status::kOpenError;
return;
}
const auto fmap =
reinterpret_cast<const struct fmap*>(image_fmap_aligned.data());
// The firmware file's self reported size should not be larger
// than the file size.
if (fmap->size > image.length()) {
LOG(ERROR) << "FMAP reported an image size of " << fmap->size
<< ", which is larger than the entire file size, "
<< image.length() << ", for '" << path_.value() << "'.";
status_ = Status::kBadFmap;
return;
}
if (!DecodeVersionFromArea(image, fmap, kFmapRoIdLabel,
&version_.ro_version)) {
status_ = Status::kBadFmap;
return;
}
if (!DecodeVersionFromArea(image, fmap, kFmapRwIdLabel,
&version_.rw_version)) {
status_ = Status::kBadFmap;
return;
}
status_ = Status::kOk;
}
} // namespace biod