/* * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2006 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2014 Intel, Inc. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #ifdef HAVE_STDIO_H # include #endif /* HAVE_STDIO_H */ #include #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ #include #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ #include "opal/util/crc.h" #if (OPAL_ALIGNMENT_LONG == 8) # define OPAL_CRC_WORD_MASK_ 0x7 #elif (OPAL_ALIGNMENT_LONG == 4) # define OPAL_CRC_WORD_MASK_ 0x3 #else # define OPAL_CRC_WORD_MASK_ 0xFFFF #endif #define WORDALIGNED(v) (((intptr_t) v & OPAL_CRC_WORD_MASK_) ? false : true) #define INTALIGNED(v) (((intptr_t) v & 3) ? false : true) /* * this version of bcopy_csum() looks a little too long, but it * handles cumulative checksumming for arbitrary lengths and address * alignments as best as it can; the contents of lastPartialLong and * lastPartialLength are updated to reflected the last partial word's * value and length (in bytes) -- this should allow proper handling of * checksumming contiguous or noncontiguous buffers via multiple calls * of bcopy_csum() - Mitch */ unsigned long opal_bcopy_csum_partial(const void *source, void *destination, size_t copylen, size_t csumlen, unsigned long *lastPartialLong, size_t *lastPartialLength) { unsigned long *src = (unsigned long *) source; unsigned long *dest = (unsigned long *) destination; unsigned long csum = 0; size_t csumlenresidue; unsigned long i, temp; csumlenresidue = (csumlen > copylen) ? (csumlen - copylen) : 0; temp = *lastPartialLong; if (WORDALIGNED(source) && WORDALIGNED(dest)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); dest = (unsigned long *) ((char *) dest + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); copylen -= sizeof(unsigned long) - *lastPartialLength; /* now we have an unaligned source and an unaligned destination */ for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialLong = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned long *) ((char *) src + copylen); dest = (unsigned long *) ((char *) dest + copylen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += copylen; copylen = 0; } } else { /* fast path... */ size_t numLongs = copylen / sizeof(unsigned long); for (i = 0; i < numLongs; i++) { csum += *src; *dest++ = *src++; } *lastPartialLong = 0; *lastPartialLength = 0; if (WORDALIGNED(copylen) && (csumlenresidue == 0)) { return (csum); } else { copylen -= i * sizeof(unsigned long); } } } else if (WORDALIGNED(source)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); dest = (unsigned long *) ((char *) dest + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); copylen -= sizeof(unsigned long) - *lastPartialLength; /* now we have an unaligned source and an unknown alignment for our destination */ if (WORDALIGNED(dest)) { size_t numLongs = copylen / sizeof(unsigned long); for (i = 0; i < numLongs; i++) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; *dest++ = temp; } copylen -= i * sizeof(unsigned long); } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } } *lastPartialLong = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned long *) ((char *) src + copylen); dest = (unsigned long *) ((char *) dest + copylen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { temp = *src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLong = 0; *lastPartialLength = 0; } } else if (WORDALIGNED(dest)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); dest = (unsigned long *) ((char *) dest + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); copylen -= sizeof(unsigned long) - *lastPartialLength; /* now we have a source of unknown alignment and a unaligned destination */ if (WORDALIGNED(src)) { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { temp = *src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLong = 0; *lastPartialLength = 0; } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialLong = 0; } } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned long *) ((char *) src + copylen); dest = (unsigned long *) ((char *) dest + copylen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; *dest++ = temp; } *lastPartialLength = 0; *lastPartialLong = 0; } } else { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); dest = (unsigned long *) ((char *) dest + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); copylen -= sizeof(unsigned long) - *lastPartialLength; /* now we have an unknown alignment for our source and destination */ if (WORDALIGNED(src) && WORDALIGNED(dest)) { size_t numLongs = copylen / sizeof(unsigned long); for (i = 0; i < numLongs; i++) { csum += *src; *dest++ = *src++; } copylen -= i * sizeof(unsigned long); } else { /* safe but slower for all other alignments */ for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } } *lastPartialLong = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned long *) ((char *) src + copylen); dest = (unsigned long *) ((char *) dest + copylen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialLong = 0; } } /* if copylen is non-zero there was a bit left, less than an unsigned long's worth */ if ((copylen != 0) && (csumlenresidue == 0)) { temp = *lastPartialLong; if (*lastPartialLength) { if (copylen >= (sizeof(unsigned long) - *lastPartialLength)) { /* copy all remaining bytes from src to dest */ unsigned long copytemp = 0; memcpy(©temp, src, copylen); memcpy(dest, ©temp, copylen); /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += (temp - *lastPartialLong); copylen -= sizeof(unsigned long) - *lastPartialLength; src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); *lastPartialLength = copylen; /* reset temp, and calculate next partial word */ temp = 0; if (copylen) { memcpy(&temp, src, copylen); } /* add it to the the checksum */ csum += temp; *lastPartialLong = temp; } else { /* copy all remaining bytes from src to dest */ unsigned long copytemp = 0; memcpy(©temp, src, copylen); memcpy(dest, ©temp, copylen); /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += temp - *lastPartialLong; *lastPartialLong = temp; *lastPartialLength += copylen; } } else { /* fast path... */ /* temp and *lastPartialLong are 0 if *lastPartialLength is 0... */ memcpy(&temp, src, copylen); csum += temp; memcpy(dest, &temp, copylen); *lastPartialLong = temp; *lastPartialLength = copylen; /* done...return the checksum */ } } else if (csumlenresidue != 0) { if (copylen != 0) { temp = 0; memcpy(&temp, src, copylen); memcpy(dest, &temp, copylen); } if (csumlenresidue < (sizeof(unsigned long) - copylen - *lastPartialLength)) { temp = *lastPartialLong; memcpy(((char *) &temp + *lastPartialLength), src, (copylen + csumlenresidue)); /* avoid unsigned arithmetic overflow by subtracting the old partial */ /* word from the new one before adding to the checksum... */ csum += temp - *lastPartialLong; src++; *lastPartialLong = temp; *lastPartialLength += copylen + csumlenresidue; csumlenresidue = 0; } else { /* we have enough chksum data to fill out our last partial */ /* word */ temp = *lastPartialLong; memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); /* avoid unsigned arithmetic overflow by subtracting the old partial */ /* word from the new one before adding to the checksum... */ csum += temp - *lastPartialLong; src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); csumlenresidue -= sizeof(unsigned long) - *lastPartialLength - copylen; *lastPartialLength = 0; *lastPartialLong = 0; } if (WORDALIGNED(src)) { for (i = 0; i < csumlenresidue / sizeof(unsigned long); i++) { csum += *src++; } } else { for (i = 0; i < csumlenresidue / sizeof(unsigned long); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } } csumlenresidue -= i * sizeof(unsigned long); if (csumlenresidue) { temp = 0; memcpy(&temp, src, csumlenresidue); csum += temp; *lastPartialLong = temp; *lastPartialLength = csumlenresidue; } } /* end else if (csumlenresidue != 0) */ return csum; } unsigned int opal_bcopy_uicsum_partial(const void *source, void *destination, size_t copylen, size_t csumlen, unsigned int *lastPartialInt, size_t *lastPartialLength) { unsigned int *src = (unsigned int *) source; unsigned int *dest = (unsigned int *) destination; unsigned int csum = 0; size_t csumlenresidue; unsigned long i; unsigned int temp; csumlenresidue = (csumlen > copylen) ? (csumlen - copylen) : 0; temp = *lastPartialInt; if (INTALIGNED(source) && INTALIGNED(dest)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); dest = (unsigned int *) ((char *) dest + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); copylen -= sizeof(unsigned int) - *lastPartialLength; /* now we have an unaligned source and an unaligned destination */ for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialInt = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned int *) ((char *) src + copylen); dest = (unsigned int *) ((char *) dest + copylen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += copylen; copylen = 0; } } else { /* fast path... */ size_t numLongs = copylen / sizeof(unsigned int); for (i = 0; i < numLongs; i++) { csum += *src; *dest++ = *src++; } *lastPartialInt = 0; *lastPartialLength = 0; if (INTALIGNED(copylen) && (csumlenresidue == 0)) { return (csum); } else { copylen -= i * sizeof(unsigned int); } } } else if (INTALIGNED(source)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); dest = (unsigned int *) ((char *) dest + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); copylen -= sizeof(unsigned int) - *lastPartialLength; /* now we have an unaligned source and an unknown alignment for our destination */ if (INTALIGNED(dest)) { size_t numLongs = copylen / sizeof(unsigned int); for (i = 0; i < numLongs; i++) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; *dest++ = temp; } copylen -= i * sizeof(unsigned int); } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } } *lastPartialInt = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned int *) ((char *) src + copylen); dest = (unsigned int *) ((char *) dest + copylen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { temp = *src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialInt = 0; *lastPartialLength = 0; } } else if (INTALIGNED(dest)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); dest = (unsigned int *) ((char *) dest + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); copylen -= sizeof(unsigned int) - *lastPartialLength; /* now we have a source of unknown alignment and a unaligned destination */ if (INTALIGNED(src)) { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { temp = *src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialInt = 0; *lastPartialLength = 0; } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialInt = 0; } } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned int *) ((char *) src + copylen); dest = (unsigned int *) ((char *) dest + copylen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; *dest++ = temp; } *lastPartialLength = 0; *lastPartialInt = 0; } } else { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (copylen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); memcpy(dest, ((char *) &temp + *lastPartialLength), (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); dest = (unsigned int *) ((char *) dest + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); copylen -= sizeof(unsigned int) - *lastPartialLength; /* now we have an unknown alignment for our source and destination */ if (INTALIGNED(src) && INTALIGNED(dest)) { size_t numLongs = copylen / sizeof(unsigned int); for (i = 0; i < numLongs; i++) { csum += *src; *dest++ = *src++; } copylen -= i * sizeof(unsigned int); } else { /* safe but slower for all other alignments */ for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } } *lastPartialInt = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); memcpy(dest, ((char *) &temp + *lastPartialLength), copylen); src = (unsigned int *) ((char *) src + copylen); dest = (unsigned int *) ((char *) dest + copylen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += copylen; copylen = 0; } } else { for (; copylen >= sizeof(*src); copylen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; memcpy(dest, &temp, sizeof(temp)); dest++; } *lastPartialLength = 0; *lastPartialInt = 0; } } /* if copylen is non-zero there was a bit left, less than an unsigned int's worth */ if ((copylen != 0) && (csumlenresidue == 0)) { temp = *lastPartialInt; if (*lastPartialLength) { if (copylen >= (sizeof(unsigned int) - *lastPartialLength)) { /* copy all remaining bytes from src to dest */ unsigned int copytemp = 0; memcpy(©temp, src, copylen); memcpy(dest, ©temp, copylen); /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += (temp - *lastPartialInt); copylen -= sizeof(unsigned int) - *lastPartialLength; src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); *lastPartialLength = copylen; /* reset temp, and calculate next partial word */ temp = 0; if (copylen) { memcpy(&temp, src, copylen); } /* add it to the the checksum */ csum += temp; *lastPartialInt = temp; } else { /* copy all remaining bytes from src to dest */ unsigned int copytemp = 0; memcpy(©temp, src, copylen); memcpy(dest, ©temp, copylen); /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, copylen); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += temp - *lastPartialInt; *lastPartialInt = temp; *lastPartialLength += copylen; } } else { /* fast path... */ /* temp and *lastPartialInt are 0 if *lastPartialLength is 0... */ memcpy(&temp, src, copylen); csum += temp; memcpy(dest, &temp, copylen); *lastPartialInt = temp; *lastPartialLength = copylen; /* done...return the checksum */ } } else if (csumlenresidue != 0) { if (copylen != 0) { temp = 0; memcpy(&temp, src, copylen); memcpy(dest, &temp, copylen); } if (csumlenresidue < (sizeof(unsigned int) - copylen - *lastPartialLength)) { temp = *lastPartialInt; memcpy(((char *) &temp + *lastPartialLength), src, (copylen + csumlenresidue)); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += temp - *lastPartialInt; src++; *lastPartialInt = temp; *lastPartialLength += copylen + csumlenresidue; csumlenresidue = 0; } else { /* we have enough chksum data to fill out our last partial * word */ temp = *lastPartialInt; memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); /* avoid unsigned arithmetic overflow by subtracting the old partial * word from the new one before adding to the checksum... */ csum += temp - *lastPartialInt; src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); csumlenresidue -= sizeof(unsigned int) - *lastPartialLength - copylen; *lastPartialLength = 0; *lastPartialInt = 0; } if (INTALIGNED(src)) { for (i = 0; i < csumlenresidue / sizeof(unsigned int); i++) { csum += *src++; } } else { for (i = 0; i < csumlenresidue / sizeof(unsigned int); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } } csumlenresidue -= i * sizeof(unsigned int); if (csumlenresidue) { temp = 0; memcpy(&temp, src, csumlenresidue); csum += temp; *lastPartialInt = temp; *lastPartialLength = csumlenresidue; } } /* end else if (csumlenresidue != 0) */ return csum; } /* * csum() generates a bcopy_csum() - compatible checksum that can be * called multiple times */ unsigned long opal_csum_partial(const void *source, size_t csumlen, unsigned long *lastPartialLong, size_t *lastPartialLength) { unsigned long *src = (unsigned long *) source; unsigned long csum = 0; unsigned long i, temp; temp = *lastPartialLong; if (WORDALIGNED(source)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (csumlen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); csumlen -= sizeof(unsigned long) - *lastPartialLength; /* now we have an unaligned source */ for (i = 0; i < csumlen / sizeof(unsigned long); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } csumlen -= i * sizeof(unsigned long); *lastPartialLong = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); src = (unsigned long *) ((char *) src + csumlen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += csumlen; csumlen = 0; } } else { /* fast path... */ size_t numLongs = csumlen / sizeof(unsigned long); for (i = 0; i < numLongs; i++) { csum += *src++; } *lastPartialLong = 0; *lastPartialLength = 0; if (WORDALIGNED(csumlen)) { return (csum); } else { csumlen -= i * sizeof(unsigned long); } } } else { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (csumlen >= (sizeof(unsigned long) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); csum += (temp - *lastPartialLong); csumlen -= sizeof(unsigned long) - *lastPartialLength; /* now we have a source of unknown alignment */ if (WORDALIGNED(src)) { for (i = 0; i < csumlen / sizeof(unsigned long); i++) { csum += *src++; } csumlen -= i * sizeof(unsigned long); *lastPartialLong = 0; *lastPartialLength = 0; } else { for (i = 0; i < csumlen / sizeof(unsigned long); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } csumlen -= i * sizeof(unsigned long); *lastPartialLong = 0; *lastPartialLength = 0; } } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); src = (unsigned long *) ((char *) src + csumlen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += csumlen; csumlen = 0; } } else { for (; csumlen >= sizeof(*src); csumlen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; } *lastPartialLength = 0; *lastPartialLong = 0; } } /* if csumlen is non-zero there was a bit left, less than an unsigned long's worth */ if (csumlen != 0) { temp = *lastPartialLong; if (*lastPartialLength) { if (csumlen >= (sizeof(unsigned long) - *lastPartialLength)) { /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned long) - *lastPartialLength)); csum += (temp - *lastPartialLong); csumlen -= sizeof(unsigned long) - *lastPartialLength; src = (unsigned long *) ((char *) src + sizeof(unsigned long) - *lastPartialLength); *lastPartialLength = csumlen; /* reset temp, and calculate next partial word */ temp = 0; if (csumlen) { memcpy(&temp, src, csumlen); } /* add it to the the checksum */ csum += temp; *lastPartialLong = temp; } else { /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); csum += (temp - *lastPartialLong); *lastPartialLong = temp; *lastPartialLength += csumlen; } } else { /* fast path... */ /* temp and *lastPartialLong are 0 if *lastPartialLength is 0... */ memcpy(&temp, src, csumlen); csum += temp; *lastPartialLong = temp; *lastPartialLength = csumlen; /* done...return the checksum */ } } return csum; } unsigned int opal_uicsum_partial(const void *source, size_t csumlen, unsigned int *lastPartialInt, size_t *lastPartialLength) { unsigned int *src = (unsigned int *) source; unsigned int csum = 0; unsigned int temp; unsigned long i; temp = *lastPartialInt; if (INTALIGNED(source)) { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (csumlen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); csumlen -= sizeof(unsigned int) - *lastPartialLength; /* now we have an unaligned source */ for (i = 0; i < csumlen / sizeof(unsigned int); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } csumlen -= i * sizeof(unsigned int); *lastPartialInt = 0; *lastPartialLength = 0; } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); src = (unsigned int *) ((char *) src + csumlen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += csumlen; csumlen = 0; } } else { /* fast path... */ size_t numLongs = csumlen / sizeof(unsigned int); for (i = 0; i < numLongs; i++) { csum += *src++; } *lastPartialInt = 0; *lastPartialLength = 0; if (INTALIGNED(csumlen)) { return (csum); } else { csumlen -= i * sizeof(unsigned int); } } } else { if (*lastPartialLength) { /* do we have enough data to fill out the partial word? */ if (csumlen >= (sizeof(unsigned int) - *lastPartialLength)) { /* YES, we do... */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); csum += (temp - *lastPartialInt); csumlen -= sizeof(unsigned int) - *lastPartialLength; /* now we have a source of unknown alignment */ if (INTALIGNED(src)) { for (i = 0; i < csumlen / sizeof(unsigned int); i++) { csum += *src++; } csumlen -= i * sizeof(unsigned int); *lastPartialInt = 0; *lastPartialLength = 0; } else { for (i = 0; i < csumlen / sizeof(unsigned int); i++) { memcpy(&temp, src, sizeof(temp)); csum += temp; src++; } csumlen -= i * sizeof(unsigned int); *lastPartialInt = 0; *lastPartialLength = 0; } } else { /* NO, we don't... */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); src = (unsigned int *) ((char *) src + csumlen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += csumlen; csumlen = 0; } } else { for (; csumlen >= sizeof(*src); csumlen -= sizeof(*src)) { memcpy(&temp, src, sizeof(temp)); src++; csum += temp; } *lastPartialLength = 0; *lastPartialInt = 0; } } /* if csumlen is non-zero there was a bit left, less than an unsigned int's worth */ if (csumlen != 0) { temp = *lastPartialInt; if (*lastPartialLength) { if (csumlen >= (sizeof(unsigned int) - *lastPartialLength)) { /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, (sizeof(unsigned int) - *lastPartialLength)); csum += (temp - *lastPartialInt); csumlen -= sizeof(unsigned int) - *lastPartialLength; src = (unsigned int *) ((char *) src + sizeof(unsigned int) - *lastPartialLength); *lastPartialLength = csumlen; /* reset temp, and calculate next partial word */ temp = 0; if (csumlen) { memcpy(&temp, src, csumlen); } /* add it to the the checksum */ csum += temp; *lastPartialInt = temp; } else { /* fill out rest of partial word and add to checksum */ memcpy(((char *) &temp + *lastPartialLength), src, csumlen); csum += (temp - *lastPartialInt); *lastPartialInt = temp; *lastPartialLength += csumlen; } } else { /* fast path... */ /* temp and *lastPartialInt are 0 if *lastPartialLength is 0... */ memcpy(&temp, src, csumlen); csum += temp; *lastPartialInt = temp; *lastPartialLength = csumlen; /* done...return the checksum */ } } return csum; } /* globals for CRC32 bcopy and calculation routines */ static bool _opal_crc_table_initialized = false; static unsigned int _opal_crc_table[256]; /* CRC32 table generation routine - thanks to Charles Michael Heard for his * optimized CRC32 code... */ void opal_initialize_crc_table(void) { register int i, j; register unsigned int crc_accum; for (i = 0; i < 256; i++) { crc_accum = (i << 24); for (j = 0; j < 8; j++) { if (crc_accum & 0x80000000) { crc_accum = (crc_accum << 1) ^ CRC_POLYNOMIAL; } else { crc_accum = (crc_accum << 1); } } _opal_crc_table[i] = crc_accum; } /* set global bool to true to do this work once! */ _opal_crc_table_initialized = true; return; } unsigned int opal_bcopy_uicrc_partial(const void *source, void *destination, size_t copylen, size_t crclen, unsigned int partial_crc) { size_t crclenresidue = (crclen > copylen) ? (crclen - copylen) : 0; register int i, j; register unsigned char t; unsigned int tmp; if (!_opal_crc_table_initialized) { opal_initialize_crc_table(); } if (INTALIGNED(source) && INTALIGNED(destination)) { register unsigned int *src = (unsigned int *) source; register unsigned int *dst = (unsigned int *) destination; register unsigned char *ts, *td; /* copy whole integers */ while (copylen >= sizeof(unsigned int)) { tmp = *src++; *dst++ = tmp; ts = (unsigned char *) &tmp; for (j = 0; j < (int) sizeof(unsigned int); j++) { i = ((partial_crc >> 24) ^ *ts++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } copylen -= sizeof(unsigned int); } ts = (unsigned char *) src; td = (unsigned char *) dst; /* copy partial integer */ while (copylen--) { t = *ts++; *td++ = t; i = ((partial_crc >> 24) ^ t) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } /* calculate CRC over remaining bytes... */ while (crclenresidue--) { i = ((partial_crc >> 24) ^ *ts++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } } else { register unsigned char *src = (unsigned char *) source; register unsigned char *dst = (unsigned char *) destination; while (copylen--) { t = *src++; *dst++ = t; i = ((partial_crc >> 24) ^ t) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } while (crclenresidue--) { i = ((partial_crc >> 24) ^ *src++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } } return partial_crc; } unsigned int opal_uicrc_partial(const void *source, size_t crclen, unsigned int partial_crc) { register int i, j; register unsigned char *t; unsigned int tmp; if (!_opal_crc_table_initialized) { opal_initialize_crc_table(); } if (INTALIGNED(source)) { register unsigned int *src = (unsigned int *) source; while (crclen >= sizeof(unsigned int)) { tmp = *src++; t = (unsigned char *) &tmp; for (j = 0; j < (int) sizeof(unsigned int); j++) { i = ((partial_crc >> 24) ^ *t++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } crclen -= sizeof(unsigned int); } t = (unsigned char *) src; while (crclen--) { i = ((partial_crc >> 24) ^ *t++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } } else { register unsigned char *src = (unsigned char *) source; while (crclen--) { i = ((partial_crc >> 24) ^ *src++) & 0xff; partial_crc = (partial_crc << 8) ^ _opal_crc_table[i]; } } return partial_crc; }