• 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   const static uint8_t kEndofApduSession[] = {0x5a, 0xc5, 0x00, 0xc5};
178   const static uint8_t kResetSession[] = {0x5a, 0xc4, 0x00, 0xc4};
179   const uint8_t *const message = end ? kEndofApduSession : kResetSession;
180   const uint32_t message_len =
181       end ? sizeof(kEndofApduSession) : sizeof(kResetSession);
182 
183   if (ese_error(ese)) {
184     return 0;
185   }
186 
187   ese->ops->hw_transmit(ese, message, message_len, 1);
188   if (ese_error(ese)) {
189     ALOGE("failed to transmit cooldown check");
190     return 0;
191   }
192 
193   nxp_pn80t_poll(ese, kTeq1Options.host_address, 5.0f, 0);
194   if (ese_error(ese)) {
195     ALOGE("failed to poll during cooldown");
196     return 0;
197   }
198   uint8_t rx_buf[32];
199   const uint32_t bytes_read =
200       ese->ops->hw_receive(ese, rx_buf, sizeof(rx_buf), 1);
201   if (ese_error(ese)) {
202     ALOGE("failed to receive cooldown response");
203     return 0;
204   }
205 
206   ALOGI("Requested power-down delay times (sec):");
207   /* For each tag type, walk the response to extract the value. */
208   uint32_t max_wait = 0;
209   if (bytes_read >= 0x8 && rx_buf[0] == 0xe5 && rx_buf[1] == 0x12) {
210     uint8_t *tag_ptr = &rx_buf[2];
211     while (tag_ptr < (rx_buf + bytes_read)) {
212       const uint8_t tag = *tag_ptr;
213       const uint8_t length = *(tag_ptr + 1);
214 
215       /* The cooldown timers are 32-bit values. */
216       if (length == sizeof(uint32_t)) {
217         const uint32_t *const value_ptr = (uint32_t *)(tag_ptr + 2);
218         uint32_t cooldown = ese_be32toh(*value_ptr);
219         switch (tag) {
220         case RESTRICTED_MODE_PENALTY:
221           /* This timer is in minutes, so convert it to seconds. */
222           cooldown *= 60;
223         /* Fallthrough */
224         case SECURE_TIMER:
225         case ATTACK_COUNTER:
226           ALOGI("- Timer 0x%.2X: %d", tag, cooldown);
227           if (cooldown > max_wait) {
228             max_wait = cooldown;
229           }
230           break;
231         default:
232           /* Ignore -- not a known tag. */
233           break;
234         }
235       }
236       tag_ptr += 2 + length;
237     }
238   }
239   return max_wait;
240 }
241 
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)242 uint32_t nxp_pn80t_handle_interface_call(struct EseInterface *ese,
243                                          const struct EseSgBuffer *tx_buf,
244                                          uint32_t tx_len,
245                                          struct EseSgBuffer *rx_buf,
246                                          uint32_t rx_len) {
247   /* Catch proprietary, host-targeted calls FF XX 00 00 */
248   const struct Pn80tPlatform *platform = ese->ops->opts;
249   static const uint32_t kCommandLength = 4;
250   static const uint8_t kResetCommand = 0x01;
251   static const uint8_t kGpioToggleCommand = 0xe0;
252   static const uint8_t kCooldownCommand = 0xe1;
253   uint8_t buf[kCommandLength + 1];
254   uint8_t ok[2] = {0x90, 0x00};
255   struct NxpState *ns = NXP_PN80T_STATE(ese);
256   /* Over-copy by one to make sure the command length matches. */
257   if (ese_sg_to_buf(tx_buf, tx_len, 0, sizeof(buf), buf) != kCommandLength) {
258     return 0;
259   }
260   /* Let 3 change as an argument. */
261   if (buf[0] != 0xff || buf[2] != 0x00) {
262     return 0;
263   }
264   switch (buf[1]) {
265   case kResetCommand:
266     ALOGI("interface command received: reset");
267     /* Force a hard reset by setting an error on the hw. */
268     ese_set_error(ese, 0);
269     if (nxp_pn80t_reset(ese) < 0) {
270       /* Warning, state unchanged error. */
271       ok[0] = 0x62;
272     }
273     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
274   case kGpioToggleCommand:
275     ALOGI("interface command received: gpio toggle");
276     if (platform->toggle_bootloader) {
277       int ret = platform->toggle_bootloader(ns->handle, buf[3]);
278       if (ret) {
279         /* Grab the bottom two bytes. */
280         ok[0] = (ret >> 8) & 0xff;
281         ok[1] = ret & 0xff;
282       }
283     } else {
284       /* Not found. */
285       ok[0] = 0x6a;
286       ok[1] = 0x82;
287     }
288     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(ok), ok);
289   case kCooldownCommand:
290     ALOGI("interface command received: cooldown");
291     uint8_t reply[6] = {0, 0, 0, 0, 0x90, 0x00};
292     const uint32_t cooldownSec = nxp_pn80t_send_cooldown(ese, false);
293     *(uint32_t *)(&reply[0]) = ese_htole32(cooldownSec);
294     if (ese_error(ese)) {
295       /* Return SW_UKNOWN on an ese failure. */
296       reply[sizeof(reply) - 2] = 0x6f;
297     }
298     return ese_sg_from_buf(rx_buf, rx_len, 0, sizeof(reply), reply);
299   }
300   return 0;
301 }
302 
nxp_pn80t_transceive(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)303 uint32_t nxp_pn80t_transceive(struct EseInterface *ese,
304                               const struct EseSgBuffer *tx_buf, uint32_t tx_len,
305                               struct EseSgBuffer *rx_buf, uint32_t rx_len) {
306 
307   const uint32_t recvd =
308       nxp_pn80t_handle_interface_call(ese, tx_buf, tx_len, rx_buf, rx_len);
309   if (recvd > 0) {
310     return recvd;
311   }
312   return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
313 }
314 
nxp_pn80t_close(struct EseInterface * ese)315 void nxp_pn80t_close(struct EseInterface *ese) {
316   ALOGV("%s: called", __func__);
317   struct NxpState *ns = NXP_PN80T_STATE(ese);
318   const struct Pn80tPlatform *platform = ese->ops->opts;
319   const uint32_t wait_sec = nxp_pn80t_send_cooldown(ese, true);
320 
321   /* After the cooldown, the device should go to sleep.
322    * If not post-use time is required, power down to ensure
323    * that the device is powered down when the OS is not on.
324    */
325   if (ese_error(ese) || wait_sec == 0) {
326     platform->toggle_reset(ns->handle, 0);
327     if (platform->toggle_power_req) {
328       platform->toggle_power_req(ns->handle, 0);
329     }
330     if (platform->toggle_ven) {
331       platform->toggle_ven(ns->handle, 0);
332     }
333   }
334 
335   platform->release(ns->handle);
336   ns->handle = NULL;
337 }
338 
339 const char *kNxpPn80tErrorMessages[] = {
340     /* The first three are required by teq1_transceive use. */
341     TEQ1_ERROR_MESSAGES,
342     /* The rest are pn80t impl specific. */
343     [kNxpPn80tErrorPlatformInit] = "unable to initialize platform",
344     [kNxpPn80tErrorPollRead] = "failed to read one byte",
345     [kNxpPn80tErrorReceive] = "failed to read",
346     [kNxpPn80tErrorReceiveSize] = "attempted to receive too much data",
347     [kNxpPn80tErrorTransmitSize] = "attempted to transfer too much data",
348     [kNxpPn80tErrorTransmit] = "failed to transmit",
349     [kNxpPn80tErrorResetToggle] = "failed to toggle reset",
350 };
351