• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #define LOG_TAG "libnos_datagram"
18 #include <log/log.h>
19 #include <nos/device.h>
20 
21 #include <ctype.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <getopt.h>
25 #include <linux/types.h>
26 #include <poll.h>
27 #include <pthread.h>
28 #include <stdarg.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34 #include <unistd.h>
35 
36 /*****************************************************************************/
37 /* Ideally, this should be in <linux/citadel.h> */
38 #define CITADEL_IOC_MAGIC               'c'
39 struct citadel_ioc_tpm_datagram {
40     __u64        buf;
41     __u32        len;
42     __u32        command;
43 };
44 #define CITADEL_IOC_TPM_DATAGRAM    _IOW(CITADEL_IOC_MAGIC, 1, \
45                          struct citadel_ioc_tpm_datagram)
46 #define CITADEL_IOC_RESET           _IO(CITADEL_IOC_MAGIC, 2)
47 /*****************************************************************************/
48 
49 #define DEV_CITADEL "/dev/citadel0"
50 
51 static pthread_mutex_t in_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
52 static uint8_t in_buf[MAX_DEVICE_TRANSFER];
read_datagram(void * ctx,uint32_t command,uint8_t * buf,uint32_t len)53 static int read_datagram(void *ctx, uint32_t command, uint8_t *buf, uint32_t len) {
54     struct citadel_ioc_tpm_datagram dg = {
55         .buf = (unsigned long)in_buf,
56         .len = len,
57         .command = command,
58     };
59     int ret;
60     int fd;
61 
62     if (!ctx) {
63 
64         ALOGE("%s: invalid (NULL) device\n", __func__);
65         return -ENODEV;
66     }
67     fd = *(int *)ctx;
68     if (fd < 0) {
69         ALOGE("%s: invalid device\n", __func__);
70         return -ENODEV;
71     }
72 
73     if (len > MAX_DEVICE_TRANSFER) {
74         ALOGE("%s: invalid len (%d > %d)\n", __func__,
75             len, MAX_DEVICE_TRANSFER);
76         return -E2BIG;
77     }
78 
79     /* Lock the in buffer while it is used for this transaction */
80     if (pthread_mutex_lock(&in_buf_mutex) != 0) {
81         ALOGE("%s: failed to lock in_buf_mutex: %s", __func__, strerror(errno));
82         return -errno;
83     }
84 
85     ret = ioctl(fd, CITADEL_IOC_TPM_DATAGRAM, &dg);
86     if (ret < 0) {
87         ALOGE("can't send spi message: %s", strerror(errno));
88         ret = -errno;
89         goto out;
90     }
91 
92     memcpy(buf, in_buf, len);
93 
94 out:
95     if (pthread_mutex_unlock(&in_buf_mutex) != 0) {
96         ALOGE("%s: failed to unlock in_buf_mutex: %s", __func__, strerror(errno));
97         ret = -errno;
98     }
99     return ret;
100 }
101 
102 static pthread_mutex_t out_buf_mutex = PTHREAD_MUTEX_INITIALIZER;
103 static uint8_t out_buf[MAX_DEVICE_TRANSFER];
write_datagram(void * ctx,uint32_t command,const uint8_t * buf,uint32_t len)104 static int write_datagram(void *ctx, uint32_t command, const uint8_t *buf, uint32_t len) {
105     struct citadel_ioc_tpm_datagram dg = {
106         .buf = (unsigned long)out_buf,
107         .len = len,
108         .command = command,
109     };
110     int ret;
111     int fd;
112 
113     if (!ctx) {
114         ALOGE("%s: invalid (NULL) device\n", __func__);
115         return -ENODEV;
116     }
117     fd = *(int *)ctx;
118     if (fd < 0) {
119         ALOGE("%s: invalid device\n", __func__);
120         return -ENODEV;
121     }
122 
123     if (len > MAX_DEVICE_TRANSFER) {
124         ALOGE("%s: invalid len (%d > %d)\n", __func__, len,
125             MAX_DEVICE_TRANSFER);
126         return -E2BIG;
127     }
128 
129     /* Lock the out buffer while it is used for this transaction */
130     if (pthread_mutex_lock(&out_buf_mutex) != 0) {
131         ALOGE("%s: failed to lock out_buf_mutex: %s", __func__, strerror(errno));
132         return -errno;
133     }
134 
135     memcpy(out_buf, buf, len);
136 
137     ret = ioctl(fd, CITADEL_IOC_TPM_DATAGRAM, &dg);
138     if (ret < 0) {
139         ALOGE("can't send spi message: %s", strerror(errno));
140         ret = -errno;
141         goto out;
142     }
143 
144 out:
145     if (pthread_mutex_unlock(&out_buf_mutex) != 0) {
146         ALOGE("%s: failed to unlock out_buf_mutex: %s", __func__, strerror(errno));
147         ret = -errno;
148     }
149     return ret;
150 }
151 
wait_for_interrupt(void * ctx,int msecs)152 static int wait_for_interrupt(void *ctx, int msecs) {
153     int fd = *(int *)ctx;
154     struct pollfd fds = {fd, POLLIN, 0};
155     int rv;
156 
157     rv = poll(&fds, 1 /*nfds*/, msecs);
158     if (rv < 0) {
159         ALOGE("poll: %s", strerror(errno));
160     }
161 
162     return rv;
163 }
164 
reset(void * ctx)165 static int reset(void *ctx) {
166     int ret;
167     int fd;
168 
169     if (!ctx) {
170 
171         ALOGE("%s: invalid (NULL) device\n", __func__);
172         return -ENODEV;
173     }
174     fd = *(int *)ctx;
175     if (fd < 0) {
176         ALOGE("%s: invalid device\n", __func__);
177         return -ENODEV;
178     }
179 
180     ret = ioctl(fd, CITADEL_IOC_RESET);
181     if (ret < 0) {
182         ALOGE("can't reset Citadel: %s", strerror(errno));
183         return -errno;
184     }
185     return 0;
186 }
187 
close_device(void * ctx)188 static void close_device(void *ctx) {
189     int fd;
190 
191     if (!ctx) {
192         ALOGE("%s: invalid (NULL) device (ignored)\n", __func__);
193         return;
194     }
195     fd = *(int *)ctx;
196     if (fd < 0) {
197         ALOGE("%s: invalid device (ignored)\n", __func__);
198         return;
199     }
200 
201     if (close(fd) < 0)
202         ALOGE("Problem closing device (ignored): %s", strerror(errno));
203     free(ctx);
204 }
205 
nos_device_open(const char * device_name,struct nos_device * dev)206 int nos_device_open(const char *device_name, struct nos_device *dev) {
207     int fd, *new_fd;
208 
209     fd = open(device_name ? device_name : DEV_CITADEL, O_RDWR);
210     if (fd < 0) {
211         ALOGE("can't open device: %s", strerror(errno));
212         return -errno;
213     }
214 
215     new_fd = (int *)malloc(sizeof(int));
216     if (!new_fd) {
217         ALOGE("can't malloc new fd: %s", strerror(errno));
218         close(fd);
219         return -ENOMEM;
220     }
221     *new_fd = fd;
222 
223     dev->ctx = new_fd;
224     dev->ops.read = read_datagram;
225     dev->ops.write = write_datagram;
226     dev->ops.wait_for_interrupt = wait_for_interrupt;
227     dev->ops.reset = reset;
228     dev->ops.close = close_device;
229     return 0;
230 }
231