1 /* $NetBSD: mvcesa.c,v 1.1 2012/07/27 03:00:01 kiyohara Exp $ */ 2 /* 3 * Copyright (c) 2008 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: mvcesa.c,v 1.1 2012/07/27 03:00:01 kiyohara Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/cprng.h> 34 #include <sys/device.h> 35 #include <sys/endian.h> 36 #include <sys/errno.h> 37 #include <sys/mbuf.h> 38 #include <sys/md5.h> 39 #include <sys/uio.h> 40 #include <sys/sha1.h> 41 42 #include <opencrypto/cryptodev.h> 43 #include <opencrypto/xform.h> 44 45 #include <dev/marvell/marvellreg.h> 46 #include <dev/marvell/marvellvar.h> 47 #include <dev/marvell/mvcesareg.h> 48 49 #include "locators.h" 50 51 #define MVCESA_SESSION(sid) ((sid) & 0x0fffffff) 52 #define MVCESA_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff)) 53 54 55 struct mvcesa_session { 56 int ses_used; 57 58 int ses_klen; 59 uint32_t ses_iv[4]; 60 uint32_t ses_key[8]; 61 62 uint32_t ses_hminner[5]; /* HMAC inner state */ 63 uint32_t ses_hmouter[5]; /* HMAC outer state */ 64 }; 65 66 struct mvcesa_softc { 67 device_t sc_dev; 68 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_ioh; 71 bus_dma_tag_t sc_dmat; 72 73 int sc_cid; 74 int sc_nsessions; 75 struct mvcesa_session *sc_sessions; 76 }; 77 78 static int mvcesa_match(device_t, cfdata_t, void *); 79 static void mvcesa_attach(device_t, device_t, void *); 80 81 static int mvcesa_intr(void *); 82 83 static int mvcesa_newsession(void *, u_int32_t *, struct cryptoini *); 84 static int mvcesa_freesession(void *, u_int64_t); 85 static int mvcesa_process(void *, struct cryptop *, int); 86 87 static int mvcesa_authentication(struct mvcesa_softc *, struct mvcesa_session *, 88 uint32_t, uint32_t *, uint32_t *, uint64_t, 89 int, int, char *, struct mbuf *, struct uio *); 90 static int mvcesa_des_encdec(struct mvcesa_softc *, struct mvcesa_session *, 91 uint32_t, uint32_t, uint32_t, uint32_t *, int, int, 92 char *, struct mbuf *, struct uio *); 93 94 95 CFATTACH_DECL_NEW(mvcesa_gt, sizeof(struct mvcesa_softc), 96 mvcesa_match, mvcesa_attach, NULL, NULL); 97 CFATTACH_DECL_NEW(mvcesa_mbus, sizeof(struct mvcesa_softc), 98 mvcesa_match, mvcesa_attach, NULL, NULL); 99 100 101 /* ARGSUSED */ 102 static int 103 mvcesa_match(device_t parent, cfdata_t match, void *aux) 104 { 105 struct marvell_attach_args *mva = aux; 106 107 if (strcmp(mva->mva_name, match->cf_name) != 0) 108 return 0; 109 if (mva->mva_offset == MVA_OFFSET_DEFAULT || 110 mva->mva_irq == MVA_IRQ_DEFAULT) 111 return 0; 112 113 mva->mva_size = MVCESA_SIZE; 114 return 1; 115 } 116 117 /* ARGSUSED */ 118 static void 119 mvcesa_attach(device_t parent, device_t self, void *aux) 120 { 121 struct mvcesa_softc *sc = device_private(self); 122 struct marvell_attach_args *mva = aux; 123 124 aprint_normal( 125 ": Marvell Cryptographic Engines and Security Accelerator\n"); 126 aprint_naive("\n"); 127 128 sc->sc_dev = self; 129 sc->sc_iot = mva->mva_iot; 130 /* Map I/O registers */ 131 if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset, 132 mva->mva_size, &sc->sc_ioh)) { 133 aprint_error_dev(self, "can't map registers\n"); 134 return; 135 } 136 sc->sc_dmat = mva->mva_dmat; 137 138 sc->sc_nsessions = 0; 139 140 /* Setup Opencrypto stuff */ 141 sc->sc_cid = crypto_get_driverid(0); 142 if (sc->sc_cid < 0) { 143 aprint_error_dev(self, "couldn't get crypto driver id\n"); 144 return; 145 } 146 crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0, 147 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 148 crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0, 149 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 150 #if __DMA_notyet__ 151 /* 152 * Don't know how to process to AES CBC in PIO-mode. 153 * I havn't found IV registers. 154 */ 155 crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, 156 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 157 #endif 158 crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0, 159 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 160 crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, 161 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 162 crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0, 163 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 164 crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, 165 mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc); 166 167 /* Clear and establish interrupt */ 168 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IC, 0); 169 marvell_intr_establish(mva->mva_irq, IPL_NET, mvcesa_intr, sc); 170 171 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IM, 0); 172 } 173 174 175 static int 176 mvcesa_intr(void *arg) 177 { 178 #if 0 179 struct mvcesa_softc *sc = (struct mvcesa_softc *)arg; 180 #endif 181 int handled = 0; 182 183 return handled; 184 } 185 186 187 /* 188 * Opencrypto functions 189 */ 190 /* 191 * Allocate a new 'session' and return an encoded session id. 'sidp' 192 * contains our registration id, and should contain an encoded session 193 * id on successful allocation. 194 */ 195 static int 196 mvcesa_newsession(void *arg, u_int32_t *sidp, struct cryptoini *cri) 197 { 198 struct mvcesa_softc *sc = (struct mvcesa_softc *)arg; 199 struct cryptoini *c; 200 struct mvcesa_session *ses = NULL; 201 int sesn, count, enc, mac, i; 202 203 KASSERT(sc != NULL /*, ("mvcesa_newsession: null softc")*/); 204 if (sidp == NULL || cri == NULL || sc == NULL) 205 return EINVAL; 206 207 for (sesn = 0; sesn < sc->sc_nsessions; sesn++) 208 if (sc->sc_sessions[sesn].ses_used == 0) { 209 ses = sc->sc_sessions + sesn; 210 break; 211 } 212 213 if (ses == NULL) { 214 sesn = sc->sc_nsessions; 215 ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF, M_NOWAIT); 216 if (ses == NULL) 217 return ENOMEM; 218 if (sesn != 0) { 219 memcpy(ses, sc->sc_sessions, sesn * sizeof(*ses)); 220 memset(sc->sc_sessions, 0, sesn * sizeof(*ses)); 221 free(sc->sc_sessions, M_DEVBUF); 222 } 223 sc->sc_sessions = ses; 224 ses = sc->sc_sessions + sesn; 225 sc->sc_nsessions++; 226 } 227 memset(ses, 0, sizeof(*ses)); 228 229 count = 0; 230 enc = mac = 0; 231 for (c = cri; c != NULL; c = c->cri_next) { 232 switch (c->cri_alg) { 233 case CRYPTO_DES_CBC: 234 case CRYPTO_3DES_CBC: 235 if (enc) 236 return EINVAL; 237 enc = 1; 238 239 cprng_fast(ses->ses_iv, 240 c->cri_alg == CRYPTO_AES_CBC ? 16 : 8); 241 242 /* Go ahead and compute key in CESA's byte order */ 243 ses->ses_klen = c->cri_klen; 244 memcpy(ses->ses_key, c->cri_key, c->cri_klen / 8); 245 switch (c->cri_alg) { 246 case CRYPTO_3DES_CBC: 247 ses->ses_key[5] = htobe32(ses->ses_key[5]); 248 ses->ses_key[4] = htobe32(ses->ses_key[4]); 249 ses->ses_key[3] = htobe32(ses->ses_key[3]); 250 ses->ses_key[2] = htobe32(ses->ses_key[2]); 251 252 /* FALLTHROUGH */ 253 case CRYPTO_DES_CBC: 254 ses->ses_key[1] = htobe32(ses->ses_key[1]); 255 ses->ses_key[0] = htobe32(ses->ses_key[0]); 256 } 257 break; 258 259 case CRYPTO_SHA1_HMAC: 260 case CRYPTO_MD5_HMAC: 261 { 262 MD5_CTX md5ctx; 263 SHA1_CTX sha1ctx; 264 int klen_bytes = c->cri_klen / 8; 265 266 KASSERT(c->cri_klen == 512); 267 268 for (i = 0; i < klen_bytes; i++) 269 c->cri_key[i] ^= HMAC_IPAD_VAL; 270 if (c->cri_alg == CRYPTO_MD5_HMAC_96) { 271 MD5Init(&md5ctx); 272 MD5Update(&md5ctx, c->cri_key, klen_bytes); 273 MD5Update(&md5ctx, hmac_ipad_buffer, 274 HMAC_BLOCK_LEN - klen_bytes); 275 memcpy(ses->ses_hminner, md5ctx.state, 276 sizeof(md5ctx.state)); 277 } else { 278 SHA1Init(&sha1ctx); 279 SHA1Update(&sha1ctx, c->cri_key, klen_bytes); 280 SHA1Update(&sha1ctx, hmac_ipad_buffer, 281 HMAC_BLOCK_LEN - klen_bytes); 282 memcpy(ses->ses_hminner, sha1ctx.state, 283 sizeof(sha1ctx.state)); 284 } 285 286 for (i = 0; i < klen_bytes; i++) 287 c->cri_key[i] ^= 288 (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); 289 if (c->cri_alg == CRYPTO_MD5_HMAC_96) { 290 MD5Init(&md5ctx); 291 MD5Update(&md5ctx, c->cri_key, klen_bytes); 292 MD5Update(&md5ctx, hmac_opad_buffer, 293 HMAC_BLOCK_LEN - klen_bytes); 294 memcpy(ses->ses_hmouter, md5ctx.state, 295 sizeof(md5ctx.state)); 296 } else { 297 SHA1Init(&sha1ctx); 298 SHA1Update(&sha1ctx, c->cri_key, klen_bytes); 299 SHA1Update(&sha1ctx, hmac_opad_buffer, 300 HMAC_BLOCK_LEN - klen_bytes); 301 memcpy(ses->ses_hmouter, sha1ctx.state, 302 sizeof(sha1ctx.state)); 303 } 304 305 for (i = 0; i < klen_bytes; i++) 306 c->cri_key[i] ^= HMAC_OPAD_VAL; 307 } 308 /* FALLTHROUGH */ 309 310 case CRYPTO_SHA1: 311 case CRYPTO_MD5: 312 if (mac) 313 return EINVAL; 314 mac = 1; 315 } 316 count++; 317 } 318 if (count > 2) { 319 mvcesa_freesession(sc, sesn); 320 return EINVAL; 321 } 322 323 *sidp = MVCESA_SID(device_unit(sc->sc_dev), sesn); 324 ses->ses_used = 1; 325 326 return 0; 327 } 328 329 /* 330 * Deallocate a session. 331 */ 332 static int 333 mvcesa_freesession(void *arg, u_int64_t tid) 334 { 335 struct mvcesa_softc *sc = (struct mvcesa_softc *)arg; 336 int session; 337 uint32_t sid = ((uint32_t)tid) & 0xffffffff; 338 339 KASSERT(sc != NULL /*, ("mvcesa_freesession: null softc")*/); 340 341 session = MVCESA_SESSION(sid); 342 if (session >= sc->sc_nsessions) 343 return EINVAL; 344 345 memset(&sc->sc_sessions[session], 0, sizeof(sc->sc_sessions[session])); 346 return (0); 347 } 348 349 static int 350 mvcesa_process(void *arg, struct cryptop *crp, int hint) 351 { 352 struct mvcesa_softc *sc = (struct mvcesa_softc *)arg; 353 struct mvcesa_session *ses; 354 struct cryptodesc *crd; 355 struct mbuf *m = NULL; 356 struct uio *uio = NULL; 357 int session; 358 char *buf = NULL; 359 360 KASSERT(sc != NULL /*, ("mvcesa_process: null softc")*/); 361 362 if (crp == NULL) 363 return EINVAL; 364 if (crp->crp_callback == NULL || sc == NULL) { 365 crp->crp_etype = EINVAL; 366 goto done; 367 } 368 369 session = MVCESA_SESSION(crp->crp_sid); 370 if (session >= sc->sc_nsessions) { 371 crp->crp_etype = ENOENT; 372 goto done; 373 } 374 ses = &sc->sc_sessions[session]; 375 376 if (crp->crp_flags & CRYPTO_F_IMBUF) 377 m = (struct mbuf *)crp->crp_buf; 378 else if (crp->crp_flags & CRYPTO_F_IOV) 379 uio = (struct uio *)crp->crp_buf; 380 else 381 buf = (char *)crp->crp_buf; 382 383 if (0 /* DMA support */) { 384 /* not yet... */ 385 386 goto done; 387 } 388 389 /* PIO operation */ 390 391 for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 392 switch (crd->crd_alg) { 393 case CRYPTO_DES_CBC: 394 case CRYPTO_3DES_CBC: 395 { 396 uint32_t alg, mode, dir, *iv, ivbuf[2]; 397 398 mode = MVCESA_DESE_C_DESMODE_CBC; 399 if (crd->crd_alg == CRYPTO_DES_CBC) 400 alg = MVCESA_DESE_C_ALGORITHM_DES; 401 else { /* CRYPTO_3DES_CBC */ 402 alg = MVCESA_DESE_C_ALGORITHM_3DES; 403 mode |= MVCESA_DESE_C_3DESMODE_EDE; 404 } 405 if (crd->crd_flags & CRD_F_ENCRYPT) { 406 dir = MVCESA_DESE_C_DIRECTION_ENC; 407 if (crd->crd_flags & CRD_F_IV_EXPLICIT) 408 iv = (uint32_t *)crd->crd_iv; 409 else 410 iv = ses->ses_iv; 411 if (!(crd->crd_flags & CRD_F_IV_PRESENT)) { 412 if (m != NULL) 413 m_copyback(m, crd->crd_inject, 414 8, iv); 415 else if (uio != NULL) 416 cuio_copyback(uio, 417 crd->crd_inject, 8, iv); 418 } 419 } else { 420 dir = MVCESA_DESE_C_DIRECTION_DEC; 421 if (crd->crd_flags & CRD_F_IV_EXPLICIT) 422 iv = (uint32_t *)crd->crd_iv; 423 else { 424 if (m != NULL) 425 m_copydata(m, crd->crd_inject, 426 8, ivbuf); 427 else if (uio != NULL) 428 cuio_copydata(uio, 429 crd->crd_inject, 8, ivbuf); 430 iv = ivbuf; 431 } 432 } 433 434 crp->crp_etype = mvcesa_des_encdec(sc, ses, 435 alg, mode, dir, iv, crd->crd_skip, crd->crd_len, 436 buf, m, uio); 437 break; 438 } 439 440 case CRYPTO_SHA1: 441 case CRYPTO_SHA1_HMAC: 442 case CRYPTO_MD5: 443 case CRYPTO_MD5_HMAC: 444 { 445 uint64_t bits; 446 uint32_t alg, *iv = NULL, digest[512 / 8 / 4], dlen; 447 448 if (crd->crd_alg == CRYPTO_SHA1 || 449 crd->crd_alg == CRYPTO_SHA1_HMAC) { 450 alg = MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1; 451 dlen = 160; 452 } else { /* CRYPTO_MD5 || CRYPTO_MD5_HMAC */ 453 alg = MVCESA_SHA1MD5I_AC_ALGORITHM_MD5; 454 dlen = 128; 455 } 456 bits = crd->crd_len << 3; 457 if (crd->crd_alg == CRYPTO_SHA1_HMAC || 458 crd->crd_alg == CRYPTO_MD5_HMAC) { 459 iv = ses->ses_hminner; 460 bits += 512; 461 } 462 463 crp->crp_etype = mvcesa_authentication(sc, ses, 464 alg, iv, digest, bits, crd->crd_skip, crd->crd_len, 465 buf, m, uio); 466 if (crp->crp_etype != 0) 467 break; 468 469 if (crd->crd_alg == CRYPTO_SHA1_HMAC || 470 crd->crd_alg == CRYPTO_MD5_HMAC) 471 crp->crp_etype = mvcesa_authentication(sc, 472 ses, alg, ses->ses_hmouter, digest, 473 512 + dlen, 0, dlen, (char *)digest, NULL, 474 NULL); 475 if (crp->crp_etype != 0) 476 break; 477 478 /* Inject the authentication data */ 479 if (buf != NULL) 480 memcpy(buf + crd->crd_inject, digest, dlen / 8); 481 else if (m != NULL) 482 m_copyback(m, crd->crd_inject, dlen / 8, 483 digest); 484 else if (uio != NULL) 485 memcpy(crp->crp_mac, digest, dlen / 8); 486 } 487 } 488 if (crp->crp_etype != 0) 489 break; 490 } 491 492 done: 493 DPRINTF(("request %08x done\n", (uint32_t)crp)); 494 crypto_done(crp); 495 return 0; 496 } 497 498 499 static int 500 mvcesa_authentication(struct mvcesa_softc *sc, struct mvcesa_session *ses, 501 uint32_t alg, uint32_t *iv, uint32_t *digest, 502 uint64_t bits, int skip, int len, char *buf, 503 struct mbuf *m, struct uio *uio) 504 { 505 uint32_t cmd, bswp, data = 0; 506 int dlen, off, i, s; 507 508 /* 509 * SHA/MD5 algorithms work in 512-bit chunks, equal to 16 words. 510 */ 511 512 KASSERT(!(len & (512 - 1)) || bits != 0); 513 KASSERT(buf != NULL || m != NULL || uio != NULL); 514 515 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC); 516 if (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION)) 517 return ERESTART; 518 519 bswp = 0; 520 if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1) { 521 dlen = 160; 522 bits = htobe64(bits); 523 #if BYTE_ORDER == LITTLE_ENDIAN 524 bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP | 525 MVCESA_SHA1MD5I_AC_IVBYTESWAP; 526 #endif 527 } else { /* MVCESA_SHA1MD5I_AC_ALGORITHM_MD5 */ 528 dlen = 128; 529 bits = htole64(bits); 530 #if BYTE_ORDER == BIG_ENDIAN 531 bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP | 532 MVCESA_SHA1MD5I_AC_IVBYTESWAP; 533 #endif 534 } 535 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC, 536 alg | bswp | MVCESA_SHA1MD5I_AC_MODE_USEIV); 537 538 if (iv != NULL) 539 bus_space_write_region_4(sc->sc_iot, sc->sc_ioh, 540 MVCESA_SHA1MD5I_IVDA, iv, dlen / 4); 541 542 off = i = 0; 543 while (1 /* CONSTCOND */) { 544 data = 0; 545 if (buf != NULL) 546 for (i = 0; i < 512 / 8 && off + i < len; i += s) { 547 s = min(sizeof(data), len - off - i); 548 memcpy(&data, buf + skip + off + i, s); 549 if (s == sizeof(data)) 550 bus_space_write_4(sc->sc_iot, 551 sc->sc_ioh, MVCESA_SHA1MD5I_DI, 552 data); 553 } 554 else if (m != NULL) 555 for (i = 0; i < 512 / 8 && off + i < len; i += s) { 556 s = min(sizeof(data), len - off - i); 557 m_copydata(m, skip + off + i, s, &data); 558 if (s == sizeof(data)) 559 bus_space_write_4(sc->sc_iot, 560 sc->sc_ioh, MVCESA_SHA1MD5I_DI, 561 data); 562 } 563 else if (uio != NULL) 564 for (i = 0; i < 512 / 8 && off + i < len; i += s) { 565 s = min(sizeof(data), len - off - i); 566 cuio_copydata(uio, skip + off + i, s, &data); 567 if (s == sizeof(data)) 568 bus_space_write_4(sc->sc_iot, 569 sc->sc_ioh, MVCESA_SHA1MD5I_DI, 570 data); 571 } 572 573 off += i; 574 if (i < 512 / 8) 575 break; 576 577 do { 578 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 579 MVCESA_SHA1MD5I_AC); 580 } while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION)); 581 582 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC, 583 alg | bswp | MVCESA_SHA1MD5I_AC_MODE_CONTINUE); 584 } 585 586 if (i < 512 / 8) { 587 *((char *)&data + (i % 4)) = 0x80; 588 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_DI, 589 data); 590 i = (i & ~3) + 4; 591 592 /* Do pad to 512 bits, if chunk size is more than 448 bits. */ 593 if (i > 448 / 8) { 594 for (; i < 512 / 8; i += 4) 595 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 596 MVCESA_SHA1MD5I_DI, 0); 597 do { 598 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 599 MVCESA_SHA1MD5I_AC); 600 } while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION)); 601 i = 0; 602 } 603 for (; i < 448 / 8; i += 4) 604 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 605 MVCESA_SHA1MD5I_DI, 0); 606 607 /* Set total bits */ 608 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCL, 609 bits & 0xffffffff); 610 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCH, 611 bits >> 32); 612 do { 613 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 614 MVCESA_SHA1MD5I_AC); 615 } while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION)); 616 } 617 618 if (digest != NULL) { 619 /* Read digest */ 620 bus_space_read_region_4(sc->sc_iot, sc->sc_ioh, 621 MVCESA_SHA1MD5I_IVDA, digest, dlen / 8 / 4); 622 #if BYTE_ORDER == LITTLE_ENDIAN 623 if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1) 624 for (i = 0; i < dlen / 8 / 4; i++) 625 digest[i] = be32toh(digest[i]); 626 #else 627 if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_MD5) 628 for (i = 0; i < dlen / 8 / 4; i++) 629 digest[i] = le32toh(digest[i]); 630 #endif 631 } 632 return 0; 633 } 634 635 static int 636 mvcesa_des_encdec(struct mvcesa_softc *sc, struct mvcesa_session *ses, 637 uint32_t alg, uint32_t mode, uint32_t dir, uint32_t *iv, 638 int skip, int len, char *buf, struct mbuf *m, struct uio *uio) 639 { 640 uint64_t iblk, oblk; 641 uint32_t cmd, bswp = 0; 642 int i, o, s; 643 644 KASSERT(buf != NULL || m != NULL || uio != NULL); 645 646 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C); 647 if (!(cmd & MVCESA_DESE_C_TERMINATION)) 648 return ERESTART; 649 650 #if BYTE_ORDER == LITTLE_ENDIAN 651 bswp = MVCESA_DESE_C_DATABYTESWAP | MVCESA_DESE_C_IVBYTESWAP | 652 MVCESA_DESE_C_OUTBYTESWAP; 653 #endif 654 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C, 655 dir | alg | mode | bswp | MVCESA_DESE_C_ALLTERMINATION); 656 657 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0L, 658 ses->ses_key[1]); 659 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0H, 660 ses->ses_key[0]); 661 if (alg == MVCESA_DESE_C_ALGORITHM_3DES) { 662 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1L, 663 ses->ses_key[3]); 664 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1H, 665 ses->ses_key[2]); 666 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2L, 667 ses->ses_key[5]); 668 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2H, 669 ses->ses_key[4]); 670 } 671 672 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVL, iv[1]); 673 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVH, iv[0]); 674 675 i = o = 0; 676 while (i < len) { 677 s = min(sizeof(iblk), len - i); 678 iblk = 0; 679 680 if (buf != NULL) 681 memcpy(&iblk, buf + skip + i, s); 682 else if (m != NULL) 683 m_copydata(m, skip + i, s, &iblk); 684 else if (uio != NULL) 685 cuio_copydata(uio, skip + i, s, &iblk); 686 687 /* 688 * We have the pipeline that two data enters. 689 */ 690 691 while (1 /* CONSTCOND */) { 692 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 693 MVCESA_DESE_C); 694 if (cmd & MVCESA_DESE_C_ALLTERMINATION) 695 /* Engine is ready. Can write two data. */ 696 break; 697 if (cmd & MVCESA_DESE_C_READALLOW) { 698 oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 699 MVCESA_DESE_DOH); 700 /* XXXX: needs barrier? */ 701 oblk |= (uint64_t)bus_space_read_4(sc->sc_iot, 702 sc->sc_ioh, MVCESA_DESE_DOL) << 32; 703 704 if (buf != NULL) 705 memcpy(buf + skip + o, &oblk, 706 sizeof(oblk)); 707 else if (m != NULL) 708 m_copydata(m, skip + o, sizeof(oblk), 709 &oblk); 710 else if (uio != NULL) 711 cuio_copyback(uio, skip + o, 712 sizeof(oblk), &oblk); 713 o += sizeof(oblk); 714 715 /* Can write one data */ 716 break; 717 } 718 } 719 720 /* 721 * Encryption/Decription calculation time is 9 cycles in DES 722 * mode and 25 cycles in 3DES mode. 723 */ 724 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBL, 725 iblk >> 32); 726 /* XXXX: needs barrier? */ 727 bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBH, 728 iblk & 0xffffffff); 729 i += s; 730 } 731 732 while (1 /* CONSTCOND */) { 733 cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 734 MVCESA_DESE_C); 735 if (cmd & (MVCESA_DESE_C_READALLOW | 736 MVCESA_DESE_C_ALLTERMINATION)) { 737 oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 738 MVCESA_DESE_DOH); 739 /* XXXX: needs barrier? */ 740 oblk |= (uint64_t)bus_space_read_4(sc->sc_iot, 741 sc->sc_ioh, MVCESA_DESE_DOL) << 32; 742 743 if (cmd & MVCESA_DESE_C_ALLTERMINATION) { 744 /* We can read IV from Data Out Registers. */ 745 if (dir == MVCESA_DESE_C_DIRECTION_ENC) 746 o -= sizeof(oblk); 747 else 748 break; 749 } 750 if (buf != NULL) 751 memcpy(buf + skip + o, &oblk, sizeof(oblk)); 752 else if (m != NULL) 753 m_copydata(m, skip + o, sizeof(oblk), &oblk); 754 else if (uio != NULL) 755 cuio_copyback(uio, skip + o, sizeof(oblk), 756 &oblk); 757 o += sizeof(oblk); 758 if (cmd & MVCESA_DESE_C_ALLTERMINATION) 759 break; 760 } 761 } 762 763 if (dir == MVCESA_DESE_C_DIRECTION_ENC) 764 memcpy(ses->ses_iv, iv, sizeof(ses->ses_iv)); 765 766 return 0; 767 } 768