xref: /aosp_15_r20/external/coreboot/tests/lib/memcpy-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /* Include memcpy() source code and alter its name to compare results with libc memcpy() */
4 #define memcpy cb_memcpy
5 #include "../lib/memcpy.c"
6 #undef memcpy
7 
8 #include <stdlib.h>
9 #include <tests/test.h>
10 #include <commonlib/helpers.h>
11 #include <types.h>
12 
13 #define MEMCPY_BUFFER_SZ (4 * KiB)
14 
15 /* Prototype of memcpy() from string.h was changed to cb_memcpy().
16    It has to be defined again. */
17 void *memcpy(void *dest, const void *src, size_t n);
18 
19 struct test_memcpy_data {
20 	u8 *buffer_from;
21 	u8 *buffer_to;
22 	u8 *helper_buffer;
23 };
24 
setup_test(void ** state)25 int setup_test(void **state)
26 {
27 	struct test_memcpy_data *s = malloc(sizeof(struct test_memcpy_data));
28 
29 	if (!s)
30 		return -1;
31 
32 	s->buffer_from = malloc(MEMCPY_BUFFER_SZ);
33 	s->buffer_to = malloc(MEMCPY_BUFFER_SZ);
34 	s->helper_buffer = malloc(MEMCPY_BUFFER_SZ);
35 
36 	if (!s->buffer_from || !s->buffer_to || !s->helper_buffer) {
37 		free(s->buffer_from);
38 		free(s->buffer_to);
39 		free(s->helper_buffer);
40 		free(s);
41 		return -1;
42 	}
43 
44 	/* Fill buffers with different values (other than zero) to make them distinguishable.
45 	   The helper buffer is often used as a backup of destination buffer so it has the
46 	   same value. */
47 	memset(s->buffer_from, 0xAB, MEMCPY_BUFFER_SZ);
48 	memset(s->buffer_to, 0xBC, MEMCPY_BUFFER_SZ);
49 	memset(s->helper_buffer, 0xBC, MEMCPY_BUFFER_SZ);
50 
51 	*state = s;
52 
53 	return 0;
54 }
55 
teardown_test(void ** state)56 int teardown_test(void **state)
57 {
58 	struct test_memcpy_data *s = *state;
59 
60 	free(s->buffer_from);
61 	free(s->buffer_to);
62 	free(s->helper_buffer);
63 	free(s);
64 
65 	return 0;
66 }
67 
68 /* Fill buffer with values from provided range [start; end] in circular way. */
fill_buffer_data_range(u8 * buffer,size_t sz,u8 start_value,u8 end_value)69 static void fill_buffer_data_range(u8 *buffer, size_t sz, u8 start_value, u8 end_value)
70 {
71 	for (size_t i = 0; i < sz; ++i)
72 		buffer[i] = (start_value + i) % (end_value - start_value + 1);
73 }
74 
test_memcpy_full_buffer_copy(void ** state)75 static void test_memcpy_full_buffer_copy(void **state)
76 {
77 	struct test_memcpy_data *s = *state;
78 	void *res_cb;
79 
80 	fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0, 255);
81 
82 	res_cb = cb_memcpy(s->buffer_to, s->buffer_from, MEMCPY_BUFFER_SZ);
83 
84 	assert_ptr_equal(s->buffer_to, res_cb);
85 	assert_memory_equal(s->buffer_from, s->buffer_to, MEMCPY_BUFFER_SZ);
86 }
87 
test_memcpy_zero_size(void ** state)88 static void test_memcpy_zero_size(void **state)
89 {
90 	struct test_memcpy_data *s = *state;
91 	void *res_cb;
92 
93 	fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 'A', 'Z');
94 
95 	/* Expect no change in destination buffer. */
96 	res_cb = cb_memcpy(s->buffer_to, s->buffer_from, 0);
97 	assert_ptr_equal(s->buffer_to, res_cb);
98 	assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ);
99 }
100 
test_memcpy_buffer_part(void ** state)101 static void test_memcpy_buffer_part(void **state)
102 {
103 	struct test_memcpy_data *s = *state;
104 	void *res_cb;
105 	const size_t offset = MEMCPY_BUFFER_SZ / 4;
106 	const size_t sz = MEMCPY_BUFFER_SZ / 2;
107 
108 	/* Self-test for correct data ranges */
109 	assert_true(offset + sz <= MEMCPY_BUFFER_SZ);
110 
111 	fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, '0', '9');
112 
113 	/* Expect only *sz* bytes of buffer to be copied. Helper buffer is used as template. */
114 	res_cb = cb_memcpy(s->buffer_to + offset, s->buffer_from, sz);
115 	assert_ptr_equal(s->buffer_to + offset, res_cb);
116 	assert_memory_equal(s->buffer_to, s->helper_buffer, offset);
117 	assert_memory_equal(s->buffer_to + offset, s->buffer_from, sz);
118 	assert_memory_equal(s->buffer_to + offset + sz, s->helper_buffer + offset + sz,
119 			    MEMCPY_BUFFER_SZ - (offset + sz));
120 }
121 
test_memcpy_buffer_part_unaligned(void ** state)122 static void test_memcpy_buffer_part_unaligned(void **state)
123 {
124 	struct test_memcpy_data *s = *state;
125 	void *res_cb;
126 	const size_t dst_offset = MEMCPY_BUFFER_SZ / 8 + 3;
127 	const size_t src_offset = MEMCPY_BUFFER_SZ / 4 - 3;
128 	const size_t sz = MEMCPY_BUFFER_SZ / 4 + 7;
129 
130 	/* Self-test for correct data ranges */
131 	assert_true(dst_offset + sz <= MEMCPY_BUFFER_SZ);
132 	assert_true(src_offset + sz <= MEMCPY_BUFFER_SZ);
133 
134 	fill_buffer_data_range(s->buffer_from, MEMCPY_BUFFER_SZ, 0x13, 0xB7);
135 
136 	res_cb = cb_memcpy(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz);
137 	assert_ptr_equal(s->buffer_to + dst_offset, res_cb);
138 	assert_memory_equal(s->buffer_to, s->helper_buffer, dst_offset);
139 	assert_memory_equal(s->buffer_to + dst_offset, s->buffer_from + src_offset, sz);
140 	assert_memory_equal(s->buffer_to + dst_offset + sz, s->helper_buffer + dst_offset + sz,
141 			    MEMCPY_BUFFER_SZ - (dst_offset + sz));
142 }
143 
test_memcpy_copy_to_itself(void ** state)144 static void test_memcpy_copy_to_itself(void **state)
145 {
146 	struct test_memcpy_data *s = *state;
147 	void *res_cb;
148 
149 	fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'G', 'X');
150 	memcpy(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ);
151 
152 	/* Expect no change in source/destination buffer. */
153 	res_cb = cb_memcpy(s->buffer_to, s->buffer_to, MEMCPY_BUFFER_SZ);
154 	assert_ptr_equal(s->buffer_to, res_cb);
155 	assert_memory_equal(s->buffer_to, s->helper_buffer, MEMCPY_BUFFER_SZ);
156 }
157 
test_memcpy_copy_part_of_itself_to_itself(void ** state)158 static void test_memcpy_copy_part_of_itself_to_itself(void **state)
159 {
160 	struct test_memcpy_data *s = *state;
161 	void *res_cb;
162 	const size_t offset = MEMCPY_BUFFER_SZ / 8;
163 	const size_t sz = MEMCPY_BUFFER_SZ - offset;
164 
165 	/* Self-test for correct data ranges */
166 	assert_true(offset + sz <= MEMCPY_BUFFER_SZ);
167 
168 	fill_buffer_data_range(s->buffer_to, MEMCPY_BUFFER_SZ, 'd', 'v');
169 	memcpy(s->helper_buffer, s->buffer_to, MEMCPY_BUFFER_SZ);
170 
171 	/* Expect only *sz* bytes to be overwritten and *offset* bytes to be left at the end. */
172 	res_cb = cb_memcpy(s->buffer_to, s->buffer_to + offset, sz);
173 	assert_ptr_equal(s->buffer_to, res_cb);
174 	assert_memory_equal(s->buffer_to, s->helper_buffer + offset, sz);
175 	assert_memory_equal(s->buffer_to + sz, s->helper_buffer + sz, offset);
176 }
177 
main(void)178 int main(void)
179 {
180 	const struct CMUnitTest tests[] = {
181 		cmocka_unit_test_setup_teardown(test_memcpy_full_buffer_copy, setup_test,
182 						teardown_test),
183 		cmocka_unit_test_setup_teardown(test_memcpy_zero_size, setup_test,
184 						teardown_test),
185 		cmocka_unit_test_setup_teardown(test_memcpy_buffer_part, setup_test,
186 						teardown_test),
187 		cmocka_unit_test_setup_teardown(test_memcpy_buffer_part_unaligned, setup_test,
188 						teardown_test),
189 		cmocka_unit_test_setup_teardown(test_memcpy_copy_to_itself, setup_test,
190 						teardown_test),
191 		cmocka_unit_test_setup_teardown(test_memcpy_copy_part_of_itself_to_itself,
192 						setup_test, teardown_test),
193 	};
194 
195 	return cb_run_group_tests(tests, NULL, NULL);
196 }
197