1/*-
2 * Copyright (C) 2001-2003 by NBMK Encryption Technologies.
3 * All rights reserved.
4 *
5 * NBMK Encryption Technologies provides no support of any kind for
6 * this software.  Questions or concerns about it may be addressed to
7 * the members of the relevant open-source community at
8 * <tech-crypto@netbsd.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
12 * met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above
18 *    copyright notice, this list of conditions and the following
19 *    disclaimer in the documentation and/or other materials provided
20 *    with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35static char const n8_id[] = "$Id: n8_SKSManager.c,v 1.1 2008/10/30 12:02:14 darran Exp $";
36/*****************************************************************************/
37/** @file n8_SKSManager.c
38 *  @brief NSP2000 SKS Manager
39 *
40 * This file is the portion of the SKS Management Interface that is always
41 * kernel resident.
42 *
43 *****************************************************************************/
44
45/*****************************************************************************
46 * Revision history:
47 * 01/21/04 jpw   Change N8_NO_64_BURST macro to come from nsp2000_regs.h
48 * 01/15/04 bac   Bug #990:  Added N8_NO_64_BURST definition and use to break up
49 *                writes to consecutive registers that are then optimized and
50 *                confusing to the NSP2000.
51 * 10/25/02 brr   Clean up function prototypes & include files.
52 * 08/23/02 bac   Fixed incorrect DBG messages that were generating compiler
53 *                warnings.
54 * 05/02/02 brr   Removed all references to queue structures.
55 * 04/02/02 spm   Changed %i escape sequence to %d, because at least BSD
56 *                kernel print doesn't understand %i.
57 * 04/01/02 spm   Moved deletion of key handle files from n8_SKSResetUnit
58 *                ioctl to N8_SKSReset API call.
59 * 03/27/02 spm   Changed all N8_HARDWARE_ERROR returns to N8_INVALID_KEY
60 *                (Bug 505) in n8_SKSWrite.  Fixed return values for
61 *                n8_SKSResetUnit, so that N8_HARDWARE_ERROR is never used
62 *                (Bug 646).
63 * 03/20/02 bac   In n8_SKSWrite added a second delay loop to ensure the SKS
64 *                Go/Busy bit is really low.  It has been observed to bounce
65 *                once after initially going low, which can then cause an
66 *                access error upon performing a write.
67 * 03/14/02 bac   Fixed n8_SKSResetUnit and n8_SKSWrite.  A reset no longer
68 *                calls write with a single word when trying to zero the entire
69 *                SKS contents.  Write grabs the lock once and does all of the
70 *                writing necessary.  If the SKS is busy, we wait a few times
71 *                rather than just returning an error or waiting blindly whether
72 *                it is busy or not.
73 * 03/12/02 brr   Updated to use AtomicLocks.
74 * 02/25/02 msz   File created by moving functions from n8_sks.c
75 ****************************************************************************/
76/** @defgroup NSP2000Driver NSP2000 Device Driver Context Memory Manager.
77 */
78
79#include "helper.h"
80#include "n8_driver_main.h"
81#include "n8_enqueue_common.h"
82#include "n8_sks.h"
83#include "n8_daemon_sks.h"
84#include "n8_sks_util.h"
85#include "n8_SKSManager.h"
86#include "nsp2000_regs.h"
87#include "n8_time.h"
88
89#define MAX_FAILURES 6
90
91
92extern int NSPcount_g;
93extern NspInstance_t NSPDeviceTable_g [];
94
95/*****************************************************************************
96 * n8_SKSWrite
97 *****************************************************************************/
98/** @ingroup n8_sks
99 * @brief Write data to the SKS PROM.
100 *
101 * More detailed description of the function including any unusual algorithms
102 * or suprising details.
103 *
104 * @param targetSKS     RO: A integer, the SKS PROM to write to.
105 * @param data_p        RO: A uint32_t pointer to the data to write.  If data_p
106 *                          is NULL, then the data_length of 0x0 will be written.
107 * @param data_length   RO: A int, the data_p buffer length in 32 bit words.
108 * @param offset        RO: A int, the SKS offset to begin the write.
109 *
110 * @par Externals:
111 *    None
112 *
113 * @return
114 *    N8_STATUS_OK indicates the write(s) successfully completed.
115 *    N8_UNEXPECTED_ERROR indicates an error writing to the SKS or that the
116 *      API was not or could not be initialized.
117 *
118 * @par Assumptions:
119 *    That the target SKS exists and that the queue control struct has a valid
120 *    pointer to the target SKS registers.
121 *****************************************************************************/
122
123N8_Status_t n8_SKSWrite(const unsigned int targetSKS,
124                        const uint32_t *data_p,
125                        const int data_length,
126                        const uint32_t offset_input,
127                        const int fromUser)
128{
129   int i = 0;
130   unsigned int failures;
131   uint32_t word;
132   N8_Status_t ret = N8_STATUS_OK;
133   uint32_t offset = offset_input;
134   uint32_t sks_status;
135
136   NspInstance_t *NSPinstance_p;
137   volatile NSP2000REGS_t *nsp;
138
139   if ((targetSKS < 0) || (targetSKS >= NSPcount_g))
140   {
141      DBG(("Failed to get control structure: %d\n", ret));
142      return N8_UNEXPECTED_ERROR;
143   }
144
145   /* assign the right control struct for the target HW */
146   NSPinstance_p = &NSPDeviceTable_g[targetSKS];
147
148/* Create a nsp pointer so the N8_NO_64_BURST macro will work */
149/* N8_NO_64_BURST is used to interleave a dummy register access between
150 * successive real 32 bit accesses that could be incorrectly "optimized" into a
151 * 64 bit burst.
152 */
153   nsp = ((NSP2000REGS_t *)(NSPinstance_p->NSPregs_p));
154
155   /* Entering critical section. */
156   N8_AtomicLock(NSPinstance_p->SKSSem);
157
158   for (i = 0; i < data_length; i++)
159   {
160      /* Get the data.  It either needs to be copied into kernel space  */
161      /* or does not need the copy and can be read directly.            */
162      if (data_p == NULL)
163      {
164         word = 0x0;
165      }
166      else if (fromUser == TRUE)
167      {
168         N8_FROM_USER(&word, &data_p[i], sizeof(word));
169      }
170      else
171      {
172         word = data_p[i];
173      }
174
175      /*
176       * Cannot access data register while
177       * PK_SKS_Go_Busy is on.
178       */
179      failures = 0;
180      if (SKS_READ_CONTROL(NSPinstance_p) & PK_SKS_Go_Busy)
181      {
182         if (++failures > MAX_FAILURES)
183         {
184            DBG(("Multiple failures waiting for SKS busy.\n"));
185            ret = N8_INVALID_KEY;
186            goto n8_SKSWrite_0;
187         }
188         /* go to sleep briefly */
189         n8_usleep(N8_MINIMUM_YIELD_USECS);
190      }
191      DBG(("Main wait for busy -- Iteration %d: Continuing "
192           "after %d failures.\n", i, failures));
193
194      /* This second wait block is here due to occasional spiking behavior in
195       * the SKS busy bit.  It has been observed that the busy bit will go low,
196       * and then briefly spike again before settling low.  This secondary wait
197       * look will ensure a single spike is detected and avoided. */
198      if (SKS_READ_CONTROL(NSPinstance_p) & PK_SKS_Go_Busy)
199      {
200         DBG(("Busy bit spike detected on iteration %d\n", i));
201      }
202      failures = 0;
203      if (SKS_READ_CONTROL(NSPinstance_p) & PK_SKS_Go_Busy)
204      {
205         if (++failures > MAX_FAILURES)
206         {
207            DBG(("Multiple failures waiting for SKS busy.\n"));
208            ret = N8_INVALID_KEY;
209            goto n8_SKSWrite_0;
210         }
211         /* go to sleep briefly */
212         n8_usleep(N8_MINIMUM_YIELD_USECS);
213      }
214      DBG(("2nd wait for busy -- Iteration %d: Continuing after %d failures.\n",
215           i, failures));
216
217      /* Clear any residual errors */
218      SKS_WRITE_CONTROL(NSPinstance_p, PK_SKS_Access_Error | PK_SKS_PROM_Error);
219      SKS_WRITE_DATA(NSPinstance_p, BE_to_uint32(&word));
220      /* Perform a dummy operation to thwart optimization that would lead to a
221       * 64-bit burst output which confuses the NSP2000.
222       * DO NOT REMOVE THIS CALL WITHOUT UNDERSTANDING THE IMPLICATIONS.
223       */
224      N8_NO_64_BURST;
225
226      /* Enable the SKS write. */
227      SKS_WRITE_CONTROL(NSPinstance_p, PK_SKS_Go_Busy |
228                        (offset++ & PK_Cmd_SKS_Offset_Mask));
229      /* Check for errors. */
230      sks_status = SKS_READ_CONTROL(NSPinstance_p);
231      if ((sks_status & PK_SKS_Access_Error) |
232          (sks_status & PK_SKS_PROM_Error))
233      {
234         DBG(("Error writing to SKS PROM. SKS Control Register = %08x\n",
235              sks_status));
236         /* Clear the error */
237         SKS_WRITE_CONTROL(NSPinstance_p,
238                           PK_SKS_Access_Error | PK_SKS_PROM_Error);
239         ret = N8_INVALID_KEY;
240         goto n8_SKSWrite_0;
241      }
242   } /* for loop */
243
244   /*
245    * wait again so that no one tries to access
246    * SKS before it is completely written.
247    */
248
249   failures = 0;
250   if (SKS_READ_CONTROL(NSPinstance_p) & PK_SKS_Go_Busy)
251   {
252      failures++;
253      if (failures >= MAX_FAILURES)
254      {
255         ret = N8_INVALID_KEY;
256         DBG(("Multiple failures waiting for SKS busy.\n"));
257         goto n8_SKSWrite_0;
258      }
259      /* go to sleep briefly */
260      n8_usleep(N8_MINIMUM_YIELD_USECS);
261   }
262
263n8_SKSWrite_0:
264   /* Leaving critical section. */
265   N8_AtomicUnlock(NSPinstance_p->SKSSem);
266   return ret;
267
268} /* n8_SKSWrite */
269
270
271/*****************************************************************************
272 * n8_SKSResetUnit
273 *****************************************************************************/
274/** @ingroup n8_sks
275 * @brief Perform SKS reset for a specific unit.
276 *
277 *  @param targetSKS           RO:  Unit number
278 *
279 * @par Externals
280 *    None
281 *
282 * @return
283 *    Status
284 *
285 * @par Errors
286 *    N8_STATUS_OK on success.<br>
287 *    N8_FILE_ERROR if errors occur while reading/writing files or
288 *                  directories.<br>
289 *
290 *
291 * @par Assumptions
292 *    <description of assumptions><br>
293 *****************************************************************************/
294
295N8_Status_t n8_SKSResetUnit(const N8_Unit_t targetSKS)
296{
297   int i;
298   N8_Status_t ret = N8_STATUS_OK;
299   NspInstance_t *NSPinstance_p;
300
301   DBG(("Reset :\n"));
302
303   /* Find out which, if any, key entries exist. Then blast 'em. */
304   DBG(("Resetting SKS %d.\n", targetSKS));
305
306
307   if ((targetSKS < 0) || (targetSKS >= NSPcount_g))
308   {
309      DBG(("Failed to get control structure: %d\n", ret));
310      return N8_INVALID_VALUE;
311   }
312
313   /* assign the right control struct for the target HW */
314   NSPinstance_p = &NSPDeviceTable_g[targetSKS];
315
316
317#ifndef SKIP_SKS_ZERO
318   /* '0' out SKS. Wipe them out. All of them. Passing NULL as the data pointer
319    * indicates to write 0x0 to entries. */
320   ret = n8_SKSWrite(targetSKS, NULL, SKS_PROM_MAX_OFFSET, 0, FALSE);
321   if (ret != N8_STATUS_OK)
322   {
323      DBG(("Error zeroing SKS in N8_SKSReset: %d\n", ret));
324      return N8_INVALID_VALUE;
325   }
326#endif
327   /* Entering critical section. */
328   N8_AtomicLock(NSPinstance_p->SKSSem);
329
330   for (i=0; i < SKS_ALLOC_UNITS_PER_PROM; i++)
331   {
332      /* Clear the SKS descriptor table. */
333      NSPinstance_p->SKS_map[i] = SKS_FREE;
334   }
335
336   /* Leaving critical section. */
337   N8_AtomicUnlock(NSPinstance_p->SKSSem);
338
339   return N8_STATUS_OK;
340} /* n8_SKSResetUnit */
341
342
343/*****************************************************************************
344 * n8_SKSAllocate
345 *****************************************************************************/
346/** @ingroup n8_sks
347 * @brief Allocate an entry for an SKS PROM.
348 *
349 * Attempts to find a best fit space in unallocated space, according to the
350 * descriptor tables, for the given key handle.
351 *
352 * @param keyHandle_p       RW: A N8_SKSKeyHandle_t.
353 *
354 * @par Externals:
355 *    None
356 * @return
357 *    N8_STATUS_OK indicates the write(s) successfully completed.
358 *    N8_UNEXPECTED_ERROR indicates an error allocating the key handle or that
359 *      the API was not or could not be initialized.
360 *
361 * @par Assumptions:
362 *    That the key handle pointer is valid.
363 *****************************************************************************/
364
365N8_Status_t n8_SKSAllocate(N8_SKSKeyHandle_t* keyHandle_p)
366{
367
368   unsigned int i;
369   unsigned int free_blocks_start_index = 0;
370   unsigned int free_blocks = 0;
371   unsigned int best_fit_index = 0;
372   unsigned int best_fit_blocks = 0;
373   unsigned int SKS_words_needed = 0;
374   unsigned int SKS_allocation_units_needed = 0;
375   NspInstance_t *NSPinstance_p;
376
377   N8_Boolean_t sks_hole_found = N8_FALSE;
378
379   uint32_t keyLength = keyHandle_p->key_length;
380   N8_SKSKeyType_t keyType = keyHandle_p->key_type;
381   int targetSKS = (int) keyHandle_p->unitID;
382   N8_Status_t ret = N8_STATUS_OK;
383
384   DBG(("N8_Allocate: \n"));
385
386   if ((targetSKS < 0) || (targetSKS >= NSPcount_g))
387   {
388      DBG(("Invalid unit: %d\n", targetSKS));
389      return N8_INVALID_VALUE;
390   }
391   /* assign the right control struct for the target HW */
392   NSPinstance_p = &NSPDeviceTable_g[targetSKS];
393
394   DBG(("SKS WORDS %d\n", SKS_RSA_DATA_LENGTH(keyLength)));
395
396   if ((ret = n8_ComputeKeyLength(keyType, keyLength,
397                                 &SKS_words_needed)) != N8_STATUS_OK)
398   {
399      DBG(("Could not compute SKS key length: %d\n", ret));
400      return ret;
401   }
402
403   DBG((
404      "Total of %d words needed in the SKS (%d) PROM for key length %d.\n",
405      SKS_words_needed, targetSKS, keyLength));
406
407   SKS_allocation_units_needed =
408      CEIL(SKS_words_needed, SKS_WORDS_PER_ALLOC_UNIT);
409
410   DBG((
411      "Total of %d allocation units needed in the SKS (%d) PROM.\n",
412      SKS_allocation_units_needed, targetSKS));
413   DBG((
414      "Looking for free blocks in descriptor %d.\n", targetSKS));
415
416   best_fit_blocks = SKS_ALLOC_UNITS_PER_PROM;
417   best_fit_index = 0;
418
419   /* Entering critical section */
420   N8_AtomicLock(NSPinstance_p->SKSSem);
421
422   /* Find the best fit for this block of words. */
423   sks_hole_found = N8_FALSE;
424   i = SKS_PROM_MIN_OFFSET;
425   while (i < SKS_ALLOC_UNITS_PER_PROM)
426   {
427      if (NSPinstance_p->SKS_map[i] == SKS_FREE)
428      {
429         DBG(("Found a free block at SKS allocation unit offset %d.\n", i));
430
431         free_blocks_start_index = i;
432         i++;
433         while ((i < SKS_ALLOC_UNITS_PER_PROM) &&
434                  ((NSPinstance_p->SKS_map[i]) == SKS_FREE))
435         {
436            i++;
437         }
438
439         free_blocks = i - free_blocks_start_index;
440
441         DBG(("Number of free allocation blocks is %d.\n", free_blocks));
442
443         /* If the number of free blocks to allocate is larger than the
444            * needed number of blocks (in groups of SKS_WORDS_PER_ALLOC_UNIT)
445            * then we can allocate this block.
446            */
447
448         if (free_blocks >= SKS_allocation_units_needed)
449         {
450            DBG(("Number of free blocks (%d) >= to needed blocks (%d).\n",
451                      free_blocks, SKS_allocation_units_needed));
452
453            sks_hole_found = N8_TRUE;
454
455            /* See if this is the smallest fit. */
456            if (free_blocks <= best_fit_blocks)
457            {
458               best_fit_index = free_blocks_start_index;
459               best_fit_blocks = free_blocks;
460            }
461         }
462         else
463         {
464            /* block is too small */
465            DBG(("Number of free blocks (%d) < to needed blocks (%d).\n",
466                      free_blocks, SKS_allocation_units_needed));
467         }
468
469      }
470      i++;
471   } /* while i < SKS_ALLOC_UNITS_PER_PROM */
472
473   if (sks_hole_found == N8_TRUE)
474   {
475      DBG((
476         "Allocating %d blocks out of %d free allocation blocks to key.\n",
477         SKS_allocation_units_needed, free_blocks));
478
479      /* Mark the blocks, in alloc unit sizes, as in use. */
480      for (i = best_fit_index;
481           i < best_fit_index + SKS_allocation_units_needed;
482           i++)
483      {
484         DBG(("Allocating block %d.\n", i));
485         NSPinstance_p->SKS_map[i] = SKS_INUSE;
486      } /* for */
487
488      /* Set the key offset. */
489      keyHandle_p->sks_offset =
490         best_fit_index * SKS_WORDS_PER_ALLOC_UNIT;
491
492      DBG(("New key handle offset will be :%d\n", keyHandle_p->sks_offset));
493   }
494   else
495   {
496      /* No space found! */
497      DBG((
498         "Unable to find enough free space in SKS to allocate for key.\n"));
499      ret = N8_NO_MORE_RESOURCE;
500   }
501
502   /* Leaving critical section. */
503   N8_AtomicUnlock(NSPinstance_p->SKSSem);
504
505   return ret;
506} /* n8_SKSAllocate */
507
508
509/*****************************************************************************
510 * n8_SKSAllocate
511 *****************************************************************************/
512/** @ingroup n8_sks
513 * @brief Set the status of an SKS entry.
514 *
515 * Sets status of SKS entry pointed to by key handle.
516 * descriptor tables, for the given key handle.
517 *
518 * @param keyHandle_p       RW: A N8_SKSKeyHandle_t.
519 * @param status            RO: The status value being set.
520 *
521 * @par Externals:
522 *    None
523 *
524 * @return
525 *    N8_STATUS_OK indicates the write(s) successfully completed.
526 *    N8_UNEXPECTED_ERROR indicates an error allocating the key handle or that
527 *      the API was not or could not be initialized.
528 *
529 * @par Assumptions:
530 *    That the key handle pointer is valid.  And that the status is valid.
531 *
532 *****************************************************************************/
533
534N8_Status_t n8_SKSsetStatus(N8_SKSKeyHandle_t *keyHandle_p,
535                                   unsigned int       status)
536{
537   int i;
538   unsigned int alloc_units_to_free = 0;
539   unsigned int num_sks_words;
540   unsigned int sks_alloc_unit_offset = 0;
541   NspInstance_t *NSPinstance_p;
542   N8_Status_t ret = N8_STATUS_OK;
543
544   if ((keyHandle_p->unitID < 0) || (keyHandle_p->unitID >= NSPcount_g))
545   {
546      DBG(("Invalid unit: %d\n", keyHandle_p->unitID));
547      return N8_INVALID_VALUE;
548   }
549   /* assign the right control struct for the target HW */
550   NSPinstance_p = &NSPDeviceTable_g[keyHandle_p->unitID];
551
552   ret = n8_ComputeKeyLength(keyHandle_p->key_type,
553                             keyHandle_p->key_length,
554                             &num_sks_words);
555   if (ret != N8_STATUS_OK)
556   {
557      return ret;
558   }
559
560   /* given the number SKS words, compute the number of allocation units */
561   alloc_units_to_free = CEIL(num_sks_words, SKS_WORDS_PER_ALLOC_UNIT);
562
563   /* given the offset in words, find the first allocation unit */
564   sks_alloc_unit_offset = keyHandle_p->sks_offset / SKS_WORDS_PER_ALLOC_UNIT;
565   if (ret != N8_STATUS_OK)
566   {
567      return ret;
568   }
569
570   N8_AtomicLock(NSPinstance_p->SKSSem);
571   for (i = 0; i < alloc_units_to_free; i++)
572   {
573      NSPinstance_p->SKS_map[sks_alloc_unit_offset + i] = status;
574   }
575   N8_AtomicUnlock(NSPinstance_p->SKSSem);
576
577   return ret;
578
579} /* n8_SKSsetStatus */
580
581