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