1// Copyright 2017 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <arch/x86/feature.h> 8#include <assert.h> 9#include <lib/unittest/unittest.h> 10#include <stddef.h> 11 12extern "C" { 13 14extern void* memcpy(void*, const void*, size_t); 15extern void* memcpy_erms(void*, const void*, size_t); 16extern void* memcpy_quad(void*, const void*, size_t); 17 18extern void* memset(void*, int, size_t); 19extern void* memset_erms(void*, int, size_t); 20extern void* memset_quad(void*, int, size_t); 21 22} 23 24typedef void* (*memcpy_func_t)(void*, const void*, size_t); 25typedef void* (*memset_func_t)(void*, int, size_t); 26 27// Initializes buf with |fill_len| bytes of |fill|, and pads the remaining 28// |len - fill_len| bytes with 0xff. 29static void initialize_buffer(char* buf, size_t len, char fill, size_t fill_len) { 30 for (size_t i = 0; i < fill_len; ++i) { 31 buf[i] = fill; 32 } 33 for (size_t i = fill_len; i < len; ++i) { 34 buf[i] = static_cast<char>(0xff); 35 } 36} 37 38static bool memcpy_func_test(memcpy_func_t cpy) { 39 BEGIN_TEST; 40 41 // Test buffers for sizes from 0 to 64 42 constexpr size_t kBufLen = 64; 43 for (size_t len = 0; len < kBufLen; ++len) { 44 // Give the buffers an extra byte so we can check we're not copying 45 // excess. 46 char src[kBufLen + 1]; 47 char dst[kBufLen + 1] = { 0 }; 48 49 initialize_buffer(src, sizeof(src), static_cast<char>(len + 1), len); 50 cpy(dst, src, len); 51 ASSERT_TRUE(!memcmp(src, dst, len), "buffer mismatch"); 52 for (size_t i = len; i < sizeof(dst); ++i) { 53 ASSERT_EQ(0, dst[i], "coppied padding"); 54 } 55 } 56 57 // Test alignment offsets relative to 8 bytes. 58 for (size_t dst_offset = 0; dst_offset < 8; ++dst_offset) { 59 for (size_t src_offset = 0; src_offset < 8; ++src_offset) { 60 // Give the buffers an extra byte so we can check we're not copying 61 // excess. 62 char src[kBufLen + 1]; 63 // Give the destination an extra 8 bytes so we don't need to worry 64 // about the case where src_offset = 0 and dst_offset = 7. 65 char dst[kBufLen + 1 + 8] = { 0 }; 66 67 for (size_t i = 0; i < src_offset; ++i) { 68 src[i] = static_cast<char>(0xff); 69 } 70 for (size_t i = src_offset; i < kBufLen; ++i) { 71 src[i] = static_cast<char>(i - src_offset + 1); 72 } 73 src[kBufLen] = static_cast<char>(0xff); 74 75 const size_t cpy_len = kBufLen - src_offset; 76 cpy(dst + dst_offset, src + src_offset, cpy_len); 77 for (size_t i = 0; i < dst_offset; ++i) { 78 ASSERT_EQ(0, dst[i], "overwrote before buffer"); 79 } 80 for (size_t i = dst_offset; i < dst_offset + cpy_len; ++i) { 81 ASSERT_EQ(static_cast<char>(i - dst_offset + 1), dst[i], "buffer mismatch"); 82 } 83 for (size_t i = dst_offset + cpy_len; i < sizeof(dst); ++i) { 84 ASSERT_EQ(0, dst[i], "overwrote after buffer"); 85 } 86 } 87 } 88 89 END_TEST; 90} 91 92static bool memset_func_test(memset_func_t set) { 93 BEGIN_TEST; 94 95 // Test buffers for sizes from 0 to 64 96 constexpr size_t kBufLen = 64; 97 for (size_t len = 0; len < kBufLen; ++len) { 98 // Give the buffer an extra byte so we can check we're not copying 99 // excess. 100 char dst[kBufLen + 1] = { 0 }; 101 102 set(dst, static_cast<int>(len + 1), len); 103 for (size_t i = 0; i < len; ++i) { 104 ASSERT_EQ(static_cast<char>(len + 1), dst[i], "buffer mismatch"); 105 } 106 for (size_t i = len; i < sizeof(dst); ++i) { 107 ASSERT_EQ(0, dst[i], "overwrote padding"); 108 } 109 } 110 111 // Test all fill values 112 for (int fill = 0; fill < 0x100; ++fill) { 113 char dst[kBufLen] = { static_cast<char>(fill + 1) }; 114 set(dst, fill, sizeof(dst)); 115 for (size_t i = 0; i < kBufLen; ++i) { 116 ASSERT_EQ(static_cast<char>(fill), dst[i], "buffer mismatch"); 117 } 118 } 119 120 // Test all alignment offsets relative to 8 bytes. 121 for (size_t offset = 0; offset < 8; ++offset) { 122 // Give the buffer an extra byte so we can check we're not copying 123 // excess. 124 char dst[kBufLen + 1] = { 0 }; 125 126 set(dst + offset, static_cast<int>(kBufLen - offset), kBufLen - offset); 127 for (size_t i = 0; i < offset; ++i) { 128 ASSERT_EQ(0, dst[i], "overwrote before buffer"); 129 } 130 for (size_t i = offset; i < kBufLen; ++i) { 131 ASSERT_EQ(static_cast<char>(kBufLen - offset), dst[i], "buffer mismatch"); 132 } 133 for (size_t i = kBufLen; i < sizeof(dst); ++i) { 134 ASSERT_EQ(0, dst[i], "overwrote after buffer"); 135 } 136 } 137 138 END_TEST; 139} 140 141static bool memcpy_test() { 142 return memcpy_func_test(memcpy); 143} 144 145static bool memcpy_quad_test() { 146 return memcpy_func_test(memcpy_quad); 147} 148 149static bool memcpy_erms_test() { 150 if (!x86_feature_test(X86_FEATURE_ERMS)) { 151 return true; 152 } 153 154 return memcpy_func_test(memcpy_erms); 155} 156 157static bool memset_test() { 158 return memset_func_test(memset); 159} 160 161static bool memset_quad_test() { 162 return memset_func_test(memset_quad); 163} 164 165static bool memset_erms_test() { 166 if (!x86_feature_test(X86_FEATURE_ERMS)) { 167 return true; 168 } 169 170 return memset_func_test(memset_erms); 171} 172 173UNITTEST_START_TESTCASE(memops_tests) 174UNITTEST("memcpy tests", memcpy_test) 175UNITTEST("memcpy_quad tests", memcpy_quad_test) 176UNITTEST("memcpy_erms tests", memcpy_erms_test) 177UNITTEST("memset tests", memset_test) 178UNITTEST("memset_quad tests", memset_quad_test) 179UNITTEST("memset_erms tests", memset_erms_test) 180UNITTEST_END_TESTCASE(memops_tests, "memops_tests", "memcpy/memset tests"); 181