• 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  * Support SPI communication with NXP PN553/PN80T secure element.
17  */
18 
19 #include "include/ese/hw/nxp/pn80t/common.h"
20 
nxp_pn80t_preprocess(const struct Teq1ProtocolOptions * const opts,struct Teq1Frame * frame,int tx)21 int nxp_pn80t_preprocess(const struct Teq1ProtocolOptions *const opts,
22                          struct Teq1Frame *frame, int tx) {
23   if (tx) {
24     /* Recompute the LRC with the NAD of 0x00 */
25     frame->header.NAD = 0x00;
26     frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
27     frame->header.NAD = opts->node_address;
28     ALOGV("interface is preprocessing outbound frame");
29   } else {
30     /* Replace the NAD with 0x00 so the LRC check passes. */
31     ALOGV("interface is preprocessing inbound frame (%x->%x)",
32           frame->header.NAD, 0x00);
33     if (frame->header.NAD != opts->host_address) {
34       ALOGV("Rewriting from unknown NAD: %x", frame->header.NAD);
35     }
36     frame->header.NAD = 0x00;
37     ALOGV("Frame length: %x", frame->header.LEN);
38   }
39   return 0;
40 }
41 
42 static const struct Teq1ProtocolOptions kTeq1Options = {
43     .host_address = 0xA5,
44     .node_address = 0x5A,
45     .bwt = 1.624f, /* cwt by default would be ~8k * 1.05s */
46     /* 1.05ms is the vendor defined ETU.  However, we use this
47      * for polling and 7 * etu (7ms) is a long time to wait
48      * between poll attempts so we divided by 7. */
49     .etu = 0.00015f, /* elementary time unit, in seconds */
50     .preprocess = &nxp_pn80t_preprocess,
51 };
52 
nxp_pn80t_open(struct EseInterface * ese,void * board)53 int nxp_pn80t_open(struct EseInterface *ese, void *board) {
54   struct NxpState *ns;
55   const struct Pn80tPlatform *platform;
56   _static_assert(sizeof(ese->pad) >= sizeof(struct NxpState *),
57                  "Pad size too small to use NXP HW");
58   platform = ese->ops->opts;
59 
60   /* Ensure all required functions exist */
61   if (!platform->initialize || !platform->release || !platform->toggle_reset ||
62       !platform->wait) {
63     ALOGE("Required functions not implemented in supplied platform");
64     ese_set_error(ese, kNxpPn80tErrorPlatformInit);
65     return -1;
66   }
67 
68   ns = NXP_PN80T_STATE(ese);
69   TEQ1_INIT_CARD_STATE((struct Teq1CardState *)(&ese->pad[0]));
70   ns->handle = platform->initialize(board);
71   if (!ns->handle) {
72     ALOGE("platform initialization failed");
73     ese_set_error(ese, kNxpPn80tErrorPlatformInit);
74     return -1;
75   }
76   /* Toggle all required power GPIOs.
77    * Each platform may prefer to handle the power
78    * muxing specific. E.g., if NFC is in use, it would
79    * be unwise to unset VEN.  However, the implementation
80    * here will attempt it if supported.
81    */
82   if (platform->toggle_ven) {
83     platform->toggle_ven(ns->handle, 1);
84   }
85   if (platform->toggle_power_req) {
86     platform->toggle_power_req(ns->handle, 1);
87   }
88   /* Power on eSE */
89   platform->toggle_reset(ns->handle, 1);
90   return 0;
91 }
92 
93 /* Used for soft-reset when possible. */
94 uint32_t nxp_pn80t_send_cooldown(struct EseInterface *ese, bool end);
95 
nxp_pn80t_reset(struct EseInterface * ese)96 int nxp_pn80t_reset(struct EseInterface *ese) {
97   const struct Pn80tPlatform *platform = ese->ops->opts;
98   struct NxpState *ns = NXP_PN80T_STATE(ese);
99 
100   /* If there is no error, perform a soft reset.
101    * If there is no cooldown time associated, go ahead and do a real
102    * reset as there is no other interface to trigger a hard reset.
103    *
104    * This avoids pulling the power when a cooldown is in progress
105    * if it is at all possible to avoid.
106    */
107   if (!ese_error(ese)) {
108     const uint32_t cooldownSec = nxp_pn80t_send_cooldown(ese, false);
109     if (!ese_error(ese) && cooldownSec > 0) {
110       return 0;
111     }
112   }
113 
114   if (platform->toggle_reset(ns->handle, 0) < 0) {
115     ese_set_error(ese, kNxpPn80tErrorResetToggle);
116     return -1;
117   }
118   if (platform->toggle_reset(ns->handle, 1) < 0) {
119     ese_set_error(ese, kNxpPn80tErrorResetToggle);
120     return -1;
121   }
122 
123   /* Start fresh with the reset. */
124   ese->error.is_err = false;
125   return 0;
126 }
127 
nxp_pn80t_poll(struct EseInterface * ese,uint8_t poll_for,float timeout,int complete)128 int nxp_pn80t_poll(struct EseInterface *ese, uint8_t poll_for, float timeout,
129                    int complete) {
130   struct NxpState *ns = NXP_PN80T_STATE(ese);
131   const struct Pn80tPlatform *platform = ese->ops->opts;
132   /* Attempt to read a 8-bit character once per 8-bit character transmission
133    * window (in seconds).
134    */
135   int intervals = (int)(0.5f + timeout / (7.0f * kTeq1Options.etu));
136   uint8_t byte = 0xff;
137   ALOGV("interface polling for start of frame/host node address: %x", poll_for);
138   /* If we had interrupts, we could just get notified by the driver. */
139   do {
140     /*
141      * In practice, if complete=true, then no transmission
142      * should attempt again until after 1000usec.
143      */
144     if (ese->ops->hw_receive(ese, &byte, 1, complete) != 1) {
145       ALOGE("failed to read one byte");
146       ese_set_error(ese, kNxpPn80tErrorPollRead);
147       return -1;
148     }
149     if (byte == poll_for) {
150       ALOGV("Polled for byte seen: %x with %d intervals remaining.", poll_for,
151             intervals);
152       ALOGV("RX[0]: %.2X", byte);
153       return 1;
154     } else {
155       ALOGV("No match (saw %x)", byte);
156     }
157     platform->wait(ns->handle,
158                    7.0f * kTeq1Options.etu * 1000000.0f); /* s -> us */
159     ALOGV("poll interval %d: no match.", intervals);
160   } while (intervals-- > 0);
161   ALOGW("polling timed out.");
162   return -1;
163 }
164 
165 /* Returns the seconds the chip has requested to stay powered for internal
166  * maintenance. This is not expected during normal operation, but it is still
167  * a possible operating response.
168  *
169  * There are three timers reserved for internal state usage which are
170  * not reliable API. As such, this function returns the maximum time
171  * in seconds that the chip would like to stay powered-on.
172  */
173 #define SECURE_TIMER 0xF1
174 #define ATTACK_COUNTER 0xF2
175 #define RESTRICTED_MODE_PENALTY 0xF3
nxp_pn80t_send_cooldown(struct EseInterface * ese,bool end)176 uint32_t nxp_pn80t_send_cooldown(struct EseInterface *ese, bool end) {
177   struct NxpState *ns = NXP_PN80T_STATE(ese);
178   const struct Pn80tPlatform *platform = ese->ops->opts;
179   const static uint8_t kEndofApduSession[] = {0x5a, 0xc5, 0x00, 0xc5};
180   const static uint8_t kResetSession[] = {0x5a, 0xc4, 0x00, 0xc4};
181   const uint8_t *const message = end ? kEndofApduSession : kResetSession;
182   const uint32_t message_len =
183       end ? sizeof(kEndofApduSession) : sizeof(kResetSession);
184 
185   if (ese_error(ese)) {
186     return 0;
187   }
188 
189   ese->ops->hw_transmit(ese, message, message_len, 1);
190   if (ese_error(ese)) {
191     ALOGE("failed to transmit cooldown check");
192     return 0;
193   }
194 
195   nxp_pn80t_poll(ese, kTeq1Options.host_address, 5.0f, 0);
196   if (ese_error(ese)) {
197     ALOGE("failed to poll during cooldown");
198     return 0;
199   }
200   uint8_t rx_buf[32];
201   const uint32_t bytes_read =
202       ese->ops->hw_receive(ese, rx_buf, sizeof(rx_buf), 1);
203   if (ese_error(ese)) {
204     ALOGE("failed to receive cooldown response");
205     return 0;
206   }
207 
208   ALOGI("Requested power-down delay times (sec):");
209   /* For each tag type, walk the response to extract the value. */
210   uint32_t max_wait = 0;
211   if (bytes_read >= 0x8 && rx_buf[0] == 0xe5 && rx_buf[1] == 0x12) {
212     uint8_t *tag_ptr = &rx_buf[2];
213     while (tag_ptr < (rx_buf + bytes_read)) {
214       const uint8_t tag = *tag_ptr;
215       const uint8_t length = *(tag_ptr + 1);
216 
217       /* The cooldown timers are 32-bit values. */
218       if (length == sizeof(uint32_t)) {
219         const uint32_t *const value_ptr = (uint32_t *)(tag_ptr + 2);
220         uint32_t cooldown = ese_be32toh(*value_ptr);
221         switch (tag) {
222         case RESTRICTED_MODE_PENALTY:
223           /* This timer is in minutes, so convert it to seconds. */
224           cooldown *= 60;
225         /* Fallthrough */
226         case SECURE_TIMER:
227         case ATTACK_COUNTER:
228           ALOGI("- Timer 0x%.2X: %d", tag, cooldown);
229           if (cooldown > max_wait) {
230             max_wait = cooldown;
231             /* Wait 25ms Guard time to make sure eSE is in DPD mode */
232             platform->wait(ns->handle, 25000);
233           }
234           break;
235         default:
236           /* Ignore -- not a known tag. */
237           break;
238         }
239       }
240       tag_ptr += 2 + length;
241     }
242   }
243   return max_wait;
244 }
245 
nxp_pn80t_handle_interface_call(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)246 uint32_t nxp_pn80t_handle_interface_call(struct EseInterface *ese,
247                                          const struct EseSgBuffer *tx_buf,
248                                          uint32_t tx_len,
249                                          struct EseSgBuffer *rx_buf,
250                                          uint32_t rx_len) {
251   /* Catch proprietary, host-targeted calls FF XX 00 00 */
252   const struct Pn80tPlatform *platform = ese->ops->opts;
253   static const uint32_t kCommandLength = 4;
254   static const uint8_t kResetCommand = 0x01;
255   static const uint8_t kGpioToggleCommand = 0xe0;
256   static const uint8_t kCooldownCommand = 0xe1;
257   uint8_t buf[kCommandLength + 1];
258   uint8_t ok[2] = {0x90, 0x00};
259   struct NxpState *ns = NXP_PN80T_STATE(ese);
260   /* Over-copy by one to make sure the command length matches. */
261   if (ese_sg_to_buf(tx_buf, tx_len, 0, sizeof(buf), buf) != kCommandLength) {
262     return 0;
263   }
264   /* Let 3 change as an argument. */
265   if (buf[0] != 0xff || buf[2] != 0x00) {
266     return 0;
267   }
268   switch (buf[1]) {
269   case kResetCommand:
270     ALOGI("interface command received: reset");
271     /* Force a hard reset by setting an error on the hw. */
272     ese_set_error(ese, 0);
273     if (nxp_pn80t_reset(ese) < 0) {
274       /* Warning, state unchanged error. */
275       ok[0] = 0x62;
276     }
277     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
278   case kGpioToggleCommand:
279     ALOGI("interface command received: gpio toggle");
280     if (platform->toggle_bootloader) {
281       int ret = platform->toggle_bootloader(ns->handle, buf[3]);
282       if (ret) {
283         /* Grab the bottom two bytes. */
284         ok[0] = (ret >> 8) & 0xff;
285         ok[1] = ret & 0xff;
286       }
287     } else {
288       /* Not found. */
289       ok[0] = 0x6a;
290       ok[1] = 0x82;
291     }
292     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
293   case kCooldownCommand:
294     ALOGI("interface command received: cooldown");
295     uint8_t reply[6] = {0, 0, 0, 0, 0x90, 0x00};
296     const uint32_t cooldownSec = nxp_pn80t_send_cooldown(ese, false);
297     *(uint32_t *)(&reply[0]) = ese_htole32(cooldownSec);
298     if (ese_error(ese)) {
299       /* Return SW_UKNOWN on an ese failure. */
300       reply[sizeof(reply) - 2] = 0x6f;
301     }
302     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(reply), reply);
303   }
304   return 0;
305 }
306 
nxp_pn80t_transceive(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)307 uint32_t nxp_pn80t_transceive(struct EseInterface *ese,
308                               const struct EseSgBuffer *tx_buf, uint32_t tx_len,
309                               struct EseSgBuffer *rx_buf, uint32_t rx_len) {
310 
311   const uint32_t recvd =
312       nxp_pn80t_handle_interface_call(ese, tx_buf, tx_len, rx_buf, rx_len);
313   if (recvd > 0) {
314     return recvd;
315   }
316   return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
317 }
318 
nxp_pn80t_close(struct EseInterface * ese)319 void nxp_pn80t_close(struct EseInterface *ese) {
320   ALOGV("%s: called", __func__);
321   struct NxpState *ns = NXP_PN80T_STATE(ese);
322   const struct Pn80tPlatform *platform = ese->ops->opts;
323   const uint32_t wait_sec = nxp_pn80t_send_cooldown(ese, true);
324 
325   /* After the cooldown, the device should go to sleep.
326    * If not post-use time is required, power down to ensure
327    * that the device is powered down when the OS is not on.
328    */
329   if (ese_error(ese) || wait_sec == 0) {
330     platform->toggle_reset(ns->handle, 0);
331     if (platform->toggle_power_req) {
332       platform->toggle_power_req(ns->handle, 0);
333     }
334     if (platform->toggle_ven) {
335       platform->toggle_ven(ns->handle, 0);
336     }
337   }
338 
339   platform->release(ns->handle);
340   ns->handle = NULL;
341 }
342 
343 const char *kNxpPn80tErrorMessages[] = {
344     /* The first three are required by teq1_transceive use. */
345     TEQ1_ERROR_MESSAGES,
346     /* The rest are pn80t impl specific. */
347     [kNxpPn80tErrorPlatformInit] = "unable to initialize platform",
348     [kNxpPn80tErrorPollRead] = "failed to read one byte",
349     [kNxpPn80tErrorReceive] = "failed to read",
350     [kNxpPn80tErrorReceiveSize] = "attempted to receive too much data",
351     [kNxpPn80tErrorTransmitSize] = "attempted to transfer too much data",
352     [kNxpPn80tErrorTransmit] = "failed to transmit",
353     [kNxpPn80tErrorResetToggle] = "failed to toggle reset",
354 };
355