/* * Copyright (c) 2018 Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #ifdef __cplusplus extern "C" { #endif /* Code taken from Yazen Ghannam , licensed GPLv2. */ #define CRC32X(crc, value) __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32W(crc, value) __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32H(crc, value) __asm__("crc32h %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32B(crc, value) __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CX(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CW(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CH(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) static inline uint16_t __get_unaligned_le16(const uint8_t *p) { return p[0] | p[1] << 8; } static inline uint32_t __get_unaligned_le32(const uint8_t *p) { return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; } static inline uint64_t __get_unaligned_le64(const uint8_t *p) { return (uint64_t)__get_unaligned_le32(p + 4) << 32 | __get_unaligned_le32(p); } static inline uint16_t get_unaligned_le16(const void *p) { return __get_unaligned_le16((const uint8_t *)p); } static inline uint32_t get_unaligned_le32(const void *p) { return __get_unaligned_le32((const uint8_t *)p); } static inline uint64_t get_unaligned_le64(const void *p) { return __get_unaligned_le64((const uint8_t *)p); } static u32 crc32_arm64_le_hw(const u8 *p, unsigned int len) { u32 crc = 0xFFFFFFFF; s64 length = len; while ((length -= sizeof(u64)) >= 0) { CRC32X(crc, get_unaligned_le64(p)); p += sizeof(u64); } /* The following is more efficient than the straight loop */ if (length & sizeof(u32)) { CRC32W(crc, get_unaligned_le32(p)); p += sizeof(u32); } if (length & sizeof(u16)) { CRC32H(crc, get_unaligned_le16(p)); p += sizeof(u16); } if (length & sizeof(u8)) CRC32B(crc, *p); return crc ^ 0xFFFFFFFF; } #ifdef __cplusplus } #endif