1 /*
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 <fcntl.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25
26 #include <linux/major.h>
27 #include <linux/mmc/ioctl.h>
28
29 #include "ipc.h"
30 #include "log.h"
31 #include "rpmb.h"
32 #include "storage.h"
33
34 #define MMC_READ_MULTIPLE_BLOCK 18
35 #define MMC_WRITE_MULTIPLE_BLOCK 25
36 #define MMC_RELIABLE_WRITE_FLAG (1 << 31)
37
38 #define MMC_RSP_PRESENT (1 << 0)
39 #define MMC_RSP_CRC (1 << 2)
40 #define MMC_RSP_OPCODE (1 << 4)
41 #define MMC_CMD_ADTC (1 << 5)
42 #define MMC_RSP_SPI_S1 (1 << 7)
43 #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
44 #define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
45
46 #define MMC_WRITE_FLAG_R 0
47 #define MMC_WRITE_FLAG_W 1
48 #define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
49
50 #define MMC_BLOCK_SIZE 512
51
52 static int rpmb_fd = -1;
53 static uint8_t read_buf[4096];
54
55 #ifdef RPMB_DEBUG
56
print_buf(const char * prefix,const uint8_t * buf,size_t size)57 static void print_buf(const char *prefix, const uint8_t *buf, size_t size)
58 {
59 size_t i;
60
61 printf("%s @%p [%zu]", prefix, buf, size);
62 for (i = 0; i < size; i++) {
63 if (i && i % 32 == 0)
64 printf("\n%*s", (int) strlen(prefix), "");
65 printf(" %02x", buf[i]);
66 }
67 printf("\n");
68 fflush(stdout);
69 }
70
71 #endif
72
73
rpmb_send(struct storage_msg * msg,const void * r,size_t req_len)74 int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
75 {
76 int rc;
77 struct {
78 struct mmc_ioc_multi_cmd multi;
79 struct mmc_ioc_cmd cmd_buf[3];
80 } mmc = {};
81 struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
82 const struct storage_rpmb_send_req *req = r;
83
84 if (req_len < sizeof(*req)) {
85 ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
86 req_len, sizeof(*req));
87 msg->result = STORAGE_ERR_NOT_VALID;
88 goto err_response;
89 }
90
91 size_t expected_len =
92 sizeof(*req) + req->reliable_write_size + req->write_size;
93 if (req_len != expected_len) {
94 ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
95 req_len, expected_len);
96 msg->result = STORAGE_ERR_NOT_VALID;
97 goto err_response;
98 }
99
100 const uint8_t *write_buf = req->payload;
101 if (req->reliable_write_size) {
102 if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
103 ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
104 msg->result = STORAGE_ERR_NOT_VALID;
105 goto err_response;
106 }
107
108 cmd->write_flag = MMC_WRITE_FLAG_RELW;
109 cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
110 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
111 cmd->blksz = MMC_BLOCK_SIZE;
112 cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
113 mmc_ioc_cmd_set_data((*cmd), write_buf);
114 #ifdef RPMB_DEBUG
115 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
116 print_buf("request: ", write_buf, req->reliable_write_size);
117 #endif
118 write_buf += req->reliable_write_size;
119 mmc.multi.num_of_cmds++;
120 cmd++;
121 }
122
123 if (req->write_size) {
124 if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
125 ALOGW("invalid write size %u\n", req->write_size);
126 msg->result = STORAGE_ERR_NOT_VALID;
127 goto err_response;
128 }
129
130 cmd->write_flag = MMC_WRITE_FLAG_W;
131 cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
132 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
133 cmd->blksz = MMC_BLOCK_SIZE;
134 cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
135 mmc_ioc_cmd_set_data((*cmd), write_buf);
136 #ifdef RPMB_DEBUG
137 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
138 print_buf("request: ", write_buf, req->write_size);
139 #endif
140 write_buf += req->write_size;
141 mmc.multi.num_of_cmds++;
142 cmd++;
143 }
144
145 if (req->read_size) {
146 if (req->read_size % MMC_BLOCK_SIZE != 0 ||
147 req->read_size > sizeof(read_buf)) {
148 ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
149 msg->result = STORAGE_ERR_NOT_VALID;
150 goto err_response;
151 }
152
153 cmd->write_flag = MMC_WRITE_FLAG_R;
154 cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
155 cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
156 cmd->blksz = MMC_BLOCK_SIZE;
157 cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
158 mmc_ioc_cmd_set_data((*cmd), read_buf);
159 #ifdef RPMB_DEBUG
160 ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
161 #endif
162 mmc.multi.num_of_cmds++;
163 cmd++;
164 }
165
166 rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
167 if (rc < 0) {
168 ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
169 msg->result = STORAGE_ERR_GENERIC;
170 goto err_response;
171 }
172 #ifdef RPMB_DEBUG
173 if (req->read_size)
174 print_buf("response: ", read_buf, req->read_size);
175 #endif
176
177 if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
178 /*
179 * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
180 * is fully synchronous in this implementation.
181 */
182 }
183
184 msg->result = STORAGE_NO_ERROR;
185 return ipc_respond(msg, read_buf, req->read_size);
186
187 err_response:
188 return ipc_respond(msg, NULL, 0);
189 }
190
191
rpmb_open(const char * rpmb_devname)192 int rpmb_open(const char *rpmb_devname)
193 {
194 int rc;
195
196 rc = open(rpmb_devname, O_RDWR, 0);
197 if (rc < 0) {
198 ALOGE("unable (%d) to open rpmb device '%s': %s\n",
199 errno, rpmb_devname, strerror(errno));
200 return rc;
201 }
202 rpmb_fd = rc;
203 return 0;
204 }
205
rpmb_close(void)206 void rpmb_close(void)
207 {
208 close(rpmb_fd);
209 rpmb_fd = -1;
210 }
211
212