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