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
12 extern "C" {
13
14 extern void* memcpy(void*, const void*, size_t);
15 extern void* memcpy_erms(void*, const void*, size_t);
16 extern void* memcpy_quad(void*, const void*, size_t);
17
18 extern void* memset(void*, int, size_t);
19 extern void* memset_erms(void*, int, size_t);
20 extern void* memset_quad(void*, int, size_t);
21
22 }
23
24 typedef void* (*memcpy_func_t)(void*, const void*, size_t);
25 typedef 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.
initialize_buffer(char * buf,size_t len,char fill,size_t fill_len)29 static 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
memcpy_func_test(memcpy_func_t cpy)38 static 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
memset_func_test(memset_func_t set)92 static 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
memcpy_test()141 static bool memcpy_test() {
142 return memcpy_func_test(memcpy);
143 }
144
memcpy_quad_test()145 static bool memcpy_quad_test() {
146 return memcpy_func_test(memcpy_quad);
147 }
148
memcpy_erms_test()149 static 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
memset_test()157 static bool memset_test() {
158 return memset_func_test(memset);
159 }
160
memset_quad_test()161 static bool memset_quad_test() {
162 return memset_func_test(memset_quad);
163 }
164
memset_erms_test()165 static 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
173 UNITTEST_START_TESTCASE(memops_tests)
174 UNITTEST("memcpy tests", memcpy_test)
175 UNITTEST("memcpy_quad tests", memcpy_quad_test)
176 UNITTEST("memcpy_erms tests", memcpy_erms_test)
177 UNITTEST("memset tests", memset_test)
178 UNITTEST("memset_quad tests", memset_quad_test)
179 UNITTEST("memset_erms tests", memset_erms_test)
180 UNITTEST_END_TESTCASE(memops_tests, "memops_tests", "memcpy/memset tests");
181