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