1/*
2 * Copyright (c) 2014, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
8 */
9
10#include <barrelfish/barrelfish.h>
11#include <bench/bench.h>
12
13#include <thc/thc.h>
14
15#include <if/omap_sdma_defs.h>
16#include <if/omap_sdma_thc.h>
17
18#include <string.h>
19
20#define MAX_FRAME_SIZE (32UL*1024*1024)
21
22static struct capref src_frame, dst_frame;
23static uint8_t *src_buf, *dst_buf;
24
25extern char logo_data[101200];
26
27static void allocate_and_map_frames(void)
28{
29    errval_t err;
30    size_t retbytes;
31
32    err = frame_alloc(&src_frame, MAX_FRAME_SIZE, &retbytes);
33    assert(err_is_ok(err));
34    assert(retbytes >= MAX_FRAME_SIZE);
35
36    err = frame_alloc(&dst_frame, MAX_FRAME_SIZE, &retbytes);
37    assert(err_is_ok(err));
38    assert(retbytes >= MAX_FRAME_SIZE);
39
40    err = vspace_map_one_frame_attr((void**)&src_buf, MAX_FRAME_SIZE, src_frame,
41                                    VREGION_FLAGS_READ_WRITE_NOCACHE,
42                                    NULL, NULL);
43    assert(err_is_ok(err));
44
45    err = vspace_map_one_frame_attr((void**)&dst_buf, MAX_FRAME_SIZE, dst_frame,
46                                    VREGION_FLAGS_READ_WRITE_NOCACHE,
47                                    NULL, NULL);
48    assert(err_is_ok(err));
49}
50
51static void fill_mem(void *buf, size_t bytesize, bool iterate, uint32_t val)
52{
53    assert(buf);
54    assert(bytesize % sizeof(uint32_t) == 0);
55
56    uint32_t *fillbuf = buf;
57    size_t size = bytesize / sizeof(uint32_t);
58
59    for(size_t i=0; i<size; i++) {
60        fillbuf[i] = (iterate) ? i : val;
61    }
62}
63
64static void test_mem(void *buf, size_t bytesize, bool iterate, uint32_t val)
65{
66    assert(buf);
67    assert(bytesize % sizeof(uint32_t) == 0);
68
69    uint32_t *fillbuf = buf;
70    size_t size = bytesize / sizeof(uint32_t);
71
72    for(size_t i=0; i<size; i++) {
73        uint32_t expected = (iterate) ? i : val;
74        if(fillbuf[i] != expected) {
75            USER_PANIC("Invalid word 0x%08x at offset %zu, expected 0x%08x\n",
76                        fillbuf[i], i, expected);
77        }
78    }
79}
80
81static void rotate_16bit_image(uint16_t *dst, uint16_t *src,
82                         omap_sdma_addr_2d_t addr,
83                         omap_sdma_count_2d_t count)
84{
85    assert(dst && src);
86    assert(count.pixel_size == omap_sdma_DATA_TYPE_16BIT);
87
88    dst += addr.x_start + (count.y_count * addr.y_start);
89    for (size_t y = 1; y <= count.y_count; y++) {
90        for (size_t x = 1; x <= count.x_count; x++) {
91            *dst = *(src++);
92            if (x < count.x_count) {
93                // within the frame
94                dst += addr.x_modify;
95            } else {
96                // at the end of a frame
97                dst += addr.y_modify;
98            }
99        }
100    }
101}
102
103static void transcopy_16bit_image(uint16_t *dst, uint16_t *src,
104                         omap_sdma_count_2d_t count,
105                         uint16_t color, uint32_t replacement)
106{
107    assert(dst && src);
108    assert(count.pixel_size == omap_sdma_DATA_TYPE_16BIT);
109
110    for (size_t y = 1; y <= count.y_count; y++) {
111        for (size_t x = 1; x <= count.x_count; x++) {
112            *(dst) = (*src != color) ? *src : replacement;
113
114            dst++; src++;
115        }
116    }
117}
118
119static void run_client(struct omap_sdma_thc_client_binding_t *cl)
120{
121    errval_t err;
122
123    debug_printf("mem_copy test\n");
124
125    ////////// Test simple memory copying of whole frame //////////
126
127    fill_mem(src_buf, MAX_FRAME_SIZE, true, 0);
128    fill_mem(dst_buf, MAX_FRAME_SIZE, false, 0);
129    cl->call_seq.mem_copy(cl, dst_frame, src_frame, &err);
130    if(err_is_fail(err)) {
131        USER_PANIC_ERR(err, "omap mem_copy");
132    }
133    test_mem(dst_buf, MAX_FRAME_SIZE, true, 0);
134
135    ////////// Test simple memory filling of whole frame //////////
136
137    debug_printf("mem_fill test\n");
138
139    cl->call_seq.mem_fill(cl, dst_frame, 0xAB, &err);
140    if(err_is_fail(err)) {
141        USER_PANIC_ERR(err, "omap mem_fill");
142    }
143    test_mem(dst_buf, MAX_FRAME_SIZE, false, 0xABABABAB);
144
145    ////////// 2D Simple Transfer Test //////////
146
147    debug_printf("mem_copy_2d test\n");
148
149    STATIC_ASSERT(MAX_FRAME_SIZE >= sizeof(logo_data), "frame too small");
150    memcpy(src_buf, logo_data, sizeof(logo_data));
151
152    omap_sdma_count_2d_t count_2d = {
153        .pixel_size = omap_sdma_DATA_TYPE_16BIT,
154        .x_count = 230,
155        .y_count = 220,
156    };
157
158    omap_sdma_addr_2d_t src_addr = {
159        .cap = src_frame,
160        .x_start = 0,
161        .y_start = 0,
162        .x_modify = 1,
163        .y_modify = 1,
164    };
165
166    omap_sdma_addr_2d_t dst_addr = src_addr;
167    dst_addr.cap = dst_frame;
168
169    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
170    if(err_is_fail(err)) {
171        USER_PANIC_ERR(err, "omap mem_copy_2d");
172    } else if (memcmp(dst_buf, logo_data, sizeof(logo_data)) != 0) {
173        USER_PANIC("dst buffer did not match image\n");
174    }
175
176    ////////// 2D Rotation Test //////////
177
178    debug_printf("mem_copy_2d rotation test\n");
179
180    dst_addr.cap = dst_frame;
181    dst_addr.x_start = count_2d.y_count-1;  // start in top right conrner
182    dst_addr.y_start = 0;
183    dst_addr.x_modify = count_2d.y_count;   // jump down one row
184    dst_addr.y_modify = -((count_2d.x_count-1) * count_2d.y_count + 1);
185
186    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
187
188    // rotate image in software for comparision
189    uint16_t *rot_data = malloc(sizeof(logo_data));
190    rotate_16bit_image(rot_data, (uint16_t*)logo_data, dst_addr, count_2d);
191
192    if(err_is_fail(err)) {
193        USER_PANIC_ERR(err, "omap mem_copy_2d");
194    } else if (memcmp(dst_buf, rot_data, sizeof(logo_data)) != 0) {
195        USER_PANIC("dst buffer did not match image\n");
196    }
197
198    free(rot_data);
199
200    ////////// 2D Constant Fill //////////
201
202    debug_printf("mem_fill_2d test\n");
203
204    // reset destination addressing mode
205    dst_addr = src_addr;
206    dst_addr.cap = dst_frame;
207
208    cl->call_seq.mem_fill_2d(cl, dst_addr, 0x4242, count_2d, &err);
209    if(err_is_fail(err)) {
210        USER_PANIC_ERR(err, "omap mem_fill_2d");
211    }
212    test_mem(dst_buf, sizeof(logo_data), false, 0x42424242);
213
214    ////////// 2D Transparent Copy //////////
215
216    debug_printf("mem_copy_2d transparent copy test\n");
217
218    dst_addr = src_addr;
219    dst_addr.cap = dst_frame;
220
221    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr,
222                             count_2d, true, 0xFFFF, &err);
223
224    // perform transparent copy in software for comparision
225    uint16_t *trans_data = malloc(sizeof(logo_data));
226    transcopy_16bit_image(trans_data, (uint16_t*)logo_data,
227                          count_2d, 0xFFFF, 0x4242);
228
229    if(err_is_fail(err)) {
230        USER_PANIC_ERR(err, "omap mem_copy_2d");
231    } else if (memcmp(dst_buf, trans_data, sizeof(logo_data)) != 0) {
232        USER_PANIC("dst buffer did not match image\n");
233    }
234
235    free(trans_data);
236
237    ////////// Invalid Capability Test //////////
238
239    debug_printf("mem_copy invalid cap test\n");
240
241    cl->call_seq.mem_fill(cl, NULL_CAP, 0, &err);
242    if (err_no(err) != OMAP_SDMA_ERR_CAP_LOOKUP) {
243        USER_PANIC_ERR(err, "invalid capability lookup\n");
244    }
245
246    ////////// Invalid Address Modifier Test //////////
247
248    debug_printf("mem_copy_2d invalid address modifier test\n");
249
250    dst_addr.x_modify = 0x10000;
251    dst_addr.y_modify = 1;
252
253    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
254    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_ADDR) {
255        USER_PANIC_ERR(err, "oversized x_modify was not detected\n");
256    }
257
258    dst_addr.x_modify = 1;
259    dst_addr.y_modify = INT32_MIN;
260
261    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
262    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_ADDR) {
263        USER_PANIC_ERR(err, "invalid dst y_modify was not detected\n");
264    }
265
266    src_addr.x_modify = 1;
267    src_addr.y_modify = INT32_MAX;
268
269    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
270    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_ADDR) {
271        USER_PANIC_ERR(err, "invalid src y_modify was not detected\n");
272    }
273
274    ////////// Invalid Frame Size Test //////////
275
276    debug_printf("mem_copy_2d invalid frame size test\n");
277
278    src_addr.x_modify = src_addr.y_modify = 1;
279    dst_addr.x_modify = dst_addr.y_modify = 1;
280
281    count_2d.x_count = 0x1000000;
282    count_2d.y_count = 1;
283
284    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
285    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_SIZE) {
286        USER_PANIC_ERR(err, "invalid x_count was not detected\n");
287    }
288
289    count_2d.y_count = 0x10000;
290    count_2d.x_count = 1;
291
292    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
293    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_SIZE) {
294        USER_PANIC_ERR(err, "invalid y_count was not detected\n");
295    }
296
297    count_2d.y_count = -1;
298    count_2d.x_count = -1;
299
300    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
301    if (err_no(err) != OMAP_SDMA_ERR_HARDWARE_LIMIT_SIZE) {
302        USER_PANIC_ERR(err, "negative count was not detected\n");
303    }
304
305    ////////// Out of Bounds Access Test //////////
306
307    debug_printf("mem_copy_2d out of bounds test\n");
308
309    count_2d.pixel_size = omap_sdma_DATA_TYPE_32BIT;
310    count_2d.x_count = MAX_FRAME_SIZE / 1024 / 4;
311    count_2d.y_count = 1024 + 1;
312
313    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
314    if (err_no(err) != OMAP_SDMA_ERR_OUT_OF_BOUNDS) {
315        USER_PANIC_ERR(err, "out of bound access was not detected\n");
316    }
317
318    count_2d.pixel_size = omap_sdma_DATA_TYPE_8BIT;
319    count_2d.x_count = MAX_FRAME_SIZE / 1024;
320    count_2d.y_count = 1024;
321
322    dst_addr.x_modify = dst_addr.y_modify = -1;
323
324    cl->call_seq.mem_copy_2d(cl, dst_addr, src_addr, count_2d, false, 0, &err);
325    if (err_no(err) != OMAP_SDMA_ERR_OUT_OF_BOUNDS) {
326        USER_PANIC_ERR(err, "out of bound access was not detected\n");
327    }
328
329    debug_printf("finished all tests successfully\n");
330}
331
332static void start_client(void)
333{
334    errval_t err;
335
336    struct omap_sdma_binding *b;
337    struct omap_sdma_thc_client_binding_t *cl;
338
339    err = omap_sdma_thc_connect_by_name("sdma",
340                                      get_default_waitset(),
341                                      IDC_BIND_FLAGS_DEFAULT,
342                                      &b);
343    if (err_is_fail(err)) {
344        USER_PANIC_ERR(err, "could not bind (thc)");
345    }
346
347    cl = malloc(sizeof(struct omap_sdma_thc_client_binding_t));
348    assert(cl != NULL);
349
350    err = omap_sdma_thc_init_client(cl, b, b);
351    if (err_is_fail(err)) {
352        USER_PANIC_ERR(err, "could not init client (thc)");
353    }
354
355    run_client(cl);
356
357    free(cl);
358}
359
360int main(int argc, char *argv[])
361{
362    allocate_and_map_frames();
363    start_client();
364
365    return 0;
366}
367