blob: 39496b4177ecf55083161a314bd6a03040fd6dfe [file] [log] [blame]
Mattias Nissler32ac6aa2015-12-11 11:37:25 +01001/*
2 * Copyright (C) 2016 The Android Open Source Project
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 <errno.h>
18#include <string.h>
19
20#include <hardware/nvram.h>
21#include <trusty/tipc.h>
22
23#define LOG_TAG "TrustyNVRAM"
24#include <log/log.h>
25
26#include <nvram/hal/nvram_device_adapter.h>
27#include <nvram/messages/blob.h>
28#include <nvram/messages/nvram_messages.h>
29
30namespace {
31
32// Character device to open for Trusty IPC connections.
33const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
34
35// App identifier of the NVRAM app.
36const char kTrustyNvramAppId[] = "com.android.trusty.nvram";
37
38// |TrustyNvramImplementation| proxies requests to the Trusty NVRAM app. It
39// serializes the request objects, sends it to the Trusty app and finally reads
40// back the result and decodes it.
41class TrustyNvramImplementation : public nvram::NvramImplementation {
42 public:
43 ~TrustyNvramImplementation() override;
44
45 void Execute(const nvram::Request& request,
46 nvram::Response* response) override;
47
48 private:
49 // Connects the IPC channel to the Trusty app if it is not already open.
50 // Returns true if the channel is open, false on errors.
51 bool Connect();
52
53 // Dispatches a command to the trust app. Returns true if successful (note
54 // that the response may still indicate an error on the Trusty side), false if
55 // there are any I/O or encoding/decoding errors.
56 bool SendRequest(const nvram::Request& request,
57 nvram::Response* response);
58
59 // The file descriptor for the IPC connection to the Trusty app.
60 int tipc_nvram_fd_ = -1;
61
62 // Response buffer. This puts a hard size limit on the responses from the
63 // Trusty app. 4096 matches the maximum IPC message size currently supported
64 // by Trusty.
65 uint8_t response_buffer_[4096];
66};
67
68TrustyNvramImplementation::~TrustyNvramImplementation() {
69 if (tipc_nvram_fd_ != -1) {
70 tipc_close(tipc_nvram_fd_);
71 tipc_nvram_fd_ = -1;
72 }
73}
74
75void TrustyNvramImplementation::Execute(const nvram::Request& request,
76 nvram::Response* response) {
77 if (!SendRequest(request, response)) {
78 response->result = NV_RESULT_INTERNAL_ERROR;
79 }
80}
81
82bool TrustyNvramImplementation::Connect() {
83 if (tipc_nvram_fd_ != -1) {
84 return true;
85 }
86
87 int rc = tipc_connect(kTrustyDeviceName, kTrustyNvramAppId);
88 if (rc < 0) {
89 ALOGE("Failed to connect to Trusty NVRAM app: %s\n", strerror(-rc));
90 return false;
91 }
92
93 tipc_nvram_fd_ = rc;
94 return true;
95}
96
97bool TrustyNvramImplementation::SendRequest(const nvram::Request& request,
98 nvram::Response* response) {
99 if (!Connect()) {
100 return false;
101 }
102
103 nvram::Blob request_buffer;
104 if (!nvram::Encode(request, &request_buffer)) {
105 ALOGE("Failed to encode NVRAM request.\n");
106 return false;
107 }
108
109 ssize_t rc =
110 write(tipc_nvram_fd_, request_buffer.data(), request_buffer.size());
111 if (rc < 0) {
112 ALOGE("Failed to send NVRAM request: %s\n", strerror(-rc));
113 return false;
114 }
115 if (static_cast<size_t>(rc) != request_buffer.size()) {
116 ALOGE("Failed to send full request buffer: %zd\n", rc);
117 return false;
118 }
119
120 rc = read(tipc_nvram_fd_, response_buffer_, sizeof(response_buffer_));
121 if (rc < 0) {
122 ALOGE("Failed to read NVRAM response: %s\n", strerror(-rc));
123 return false;
124 }
125
126 if (static_cast<size_t>(rc) >= sizeof(response_buffer_)) {
127 ALOGE("NVRAM response exceeds response buffer size.\n");
128 return false;
129 }
130
131 if (!nvram::Decode(response_buffer_, static_cast<size_t>(rc), response)) {
132 ALOGE("Failed to decode NVRAM response.\n");
133 return false;
134 }
135
136 return true;
137}
138
139} // namespace
140
141extern "C" int trusty_nvram_open(const hw_module_t* module,
142 const char* device_id,
143 hw_device_t** device_ptr) {
144 if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
145 return -EINVAL;
146 }
147
148 nvram::NvramDeviceAdapter* adapter =
149 new nvram::NvramDeviceAdapter(module, new TrustyNvramImplementation);
150 *device_ptr = adapter->as_device();
151 return 0;
152}