diff options
Diffstat (limited to 'sys/libkern')
-rw-r--r-- | sys/libkern/arm64/crc32c_armv8.S | 78 | ||||
-rw-r--r-- | sys/libkern/crc32.c | 16 |
2 files changed, 94 insertions, 0 deletions
diff --git a/sys/libkern/arm64/crc32c_armv8.S b/sys/libkern/arm64/crc32c_armv8.S new file mode 100644 index 0000000..072dfd6 --- /dev/null +++ b/sys/libkern/arm64/crc32c_armv8.S @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2017 Michael Tuexen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <machine/asm.h> +__FBSDID("$FreeBSD$"); + +/* + * uint32_t + * armv8_crc32c(uint32_t crc, const unsigned char *buf, unsigned int len) + */ + +ENTRY(armv8_crc32c) + cbz w2, end + tbz x1, #0x0, half_word_aligned + sub w2, w2, 0x1 + ldr w10, [x1], #0x1 + crc32cb w0, w0, w10 +half_word_aligned: + cmp w2, #0x2 + b.lo last_byte + tbz x1, #0x1, word_aligned + sub w2, w2, 0x2 + ldr w10, [x1], #0x2 + crc32ch w0, w0, w10 +word_aligned: + cmp w2, #0x4 + b.lo last_half_word + tbz x1, #0x2, double_word_aligned + sub w2, w2, 0x4 + ldr w10, [x1], #0x4 + crc32cw w0, w0, w10 +double_word_aligned: + lsr w9, w2, #0x3 + cbz w9, last_word +loop: + ldr x10, [x1], #0x8 + crc32cx w0, w0, x10 + subs w9, w9, #1 + b.ne loop +last_word: + tbz w2, #0x2, last_half_word + ldr w10, [x1], #0x4 + crc32cw w0, w0, w10 +last_half_word: + tbz w2, #0x1, last_byte + ldr w10, [x1], #0x2 + crc32ch w0, w0, w10 +last_byte: + tbz w2, #0x0, end + ldr w10, [x1], #0x1 + crc32cb w0, w0, w10 +end: + ret +END(armv8_crc32c) diff --git a/sys/libkern/crc32.c b/sys/libkern/crc32.c index 281c4b6..b0a8ce0 100644 --- a/sys/libkern/crc32.c +++ b/sys/libkern/crc32.c @@ -54,6 +54,10 @@ __FBSDID("$FreeBSD$"); #include <machine/specialreg.h> #endif +#if defined(__aarch64__) +#include <machine/cpu.h> +#endif + const uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, @@ -760,6 +764,18 @@ calculate_crc32c(uint32_t crc32c, return (sse42_crc32c(crc32c, buffer, length)); } else #endif +#if defined(__aarch64__) + uint64_t reg; + + /* + * We only test for CRC32 support on the CPU with index 0 assuming that + * this applies to all CPUs. + */ + reg = READ_SPECIALREG(id_aa64isar0_el1); + if (ID_AA64ISAR0_CRC32(reg) != ID_AA64ISAR0_CRC32_NONE) { + return (armv8_crc32c(crc32c, buffer, length)); + } else +#endif if (length < 4) { return (singletable_crc32c(crc32c, buffer, length)); } else { |