1/*
2 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <stdbool.h>
13#include <barrelfish/barrelfish.h>
14#include <barrelfish/waitset.h>
15#include <devif/queue_interface.h>
16#include <devif/queue_interface_backend.h>
17#include <devif/backends/debug.h>
18#include "debug.h"
19
20
21//#define DQ_ENABLE_HIST
22#define HIST_SIZE 128
23#define MAX_STR_SIZE 128
24
25/*
26 * This is a debugging interface for the device queue interface that
27 * can be used with any existing queue. It can be stacked on top
28 * to check for non valid buffer enqueues/deqeues that might happen.
29 * A not valid enqueue of a buffer is when the endpoint that enqueues
30 * the buffer does not own the buffer.
31 *
32 * We keep track of the owned buffers as a list of regions which each
33 * contains a list of memory chunks.
34 * Each chunk specifies a offset within the region and its length.
35 *
36 * When a region is registered, we add one memory chunk that describes
37 * the whole region i.e. offset=0 length= length of region
38 *
39 * If a a buffer is enqueued, it has to be contained in one of these
40 * memory chunks. The memory chunk is then altered according how
41 * the buffer is contained in the chunk. If it is at the beginning or
42 * end of the chunk, the offset/length of the chunk is changed accordingly
43 * If the buffer is in the middle of the chunk, we split the memory chunk
44 * into two new memory chunks that do not contain the buffer.
45 *
46 * If a buffer is dequeued the buffer is added to the existing memory
47 * chunks if possible, otherwise a new memory chunk is added to the
48 * list of chunks. If a buffer is dequeued that is in between two
49 * memory chunks, the memory chunks are merged to one big chunk.
50 * We might fail to find the region id in our list of regions. In this
51 * case we add the region with the deqeued offset+length as a size.
52 * We can be sure that this region exists since the devq library itself
53 * does these checks if the region is known to the endpoint. This simply
54 * means the debugging queue on top of the other queue does not have a
55 * consistant view of the registered regions (but the queue below does)
56 *
57 * When a region is deregistered, the list of chunks has to only
58 * contain a single chunk that descirbes the whole region. Otherwise
59 * the call will fail since some of the buffers are still in use.
60 *
61 */
62
63struct memory_ele {
64    genoffset_t offset;
65    genoffset_t length;
66    struct memory_ele* next;
67    struct memory_ele* prev;
68};
69
70struct memory_list {
71    regionid_t rid;
72    genoffset_t length;
73    // is a region that we did not register ourselves
74    bool not_consistent;
75    struct memory_ele* buffers;
76    struct memory_list* next; // next in list of lists
77};
78
79struct operation {
80    char str[MAX_STR_SIZE];
81    genoffset_t offset;
82    genoffset_t length;
83};
84
85struct debug_q {
86    struct devq my_q;
87    struct devq* q;
88    struct memory_list* regions; // list of lists
89    struct slab_allocator alloc;
90    struct slab_allocator alloc_list;
91    uint16_t hist_head;
92    struct operation history[HIST_SIZE];
93};
94
95static void dump_list(struct memory_list* region)
96{
97    struct memory_ele* ele = region->buffers;
98    int index = 0;
99    printf("================================================ \n");
100    while (ele != NULL) {
101        printf("Idx=%d offset=%lu length=%lu", index, ele->offset,
102               ele->length);
103        if (ele->prev != NULL) {
104
105            printf(" prev->offset=%lu prev->length=%lu", ele->prev->offset,
106                   ele->prev->length);
107        }
108        printf(" \n");
109        ele = ele->next;
110        index++;
111    }
112    printf("================================================ \n");
113}
114
115// checks if there are elements in the list that should be merged
116/*
117static void check_consistency(struct memory_list* region)
118{
119    struct memory_ele* ele = region->buffers;
120    while (ele->next != NULL) {
121        if (ele->offset + ele->length == ele->next->offset) {
122            printf("offset=%lu length=%lu \n", ele->offset, ele->length);
123            dump_list(region);
124            USER_PANIC("Found entry that should be merged \n");
125        }
126        ele = ele->next;
127    }
128}
129*/
130#ifdef DQ_ENABLE_HIST
131static void add_to_history(struct debug_q* q, genoffset_t offset,
132                           genoffset_t length, char* s)
133{
134    q->history[q->hist_head].offset = offset;
135    q->history[q->hist_head].length = length;
136    strncpy(q->history[q->hist_head].str, s, MAX_STR_SIZE);
137    q->hist_head = (q->hist_head + 1) % HIST_SIZE;
138}
139
140static void dump_history(struct debug_q* q)
141{
142    for (int i = 0; i < HIST_SIZE; i++) {
143        printf("offset=%lu length=%lu %s\n", q->history[q->hist_head].offset,
144               q->history[q->hist_head].length, q->history[q->hist_head].str);
145
146        q->hist_head = (q->hist_head + 1) % HIST_SIZE;
147    }
148}
149#endif
150/*
151static bool in_list(struct memory_list* region, genoffset_t offset,
152                    genoffset_t length)
153{
154    struct memory_ele* ele = region->buffers;
155    while (ele != NULL) {
156        if (offset >= ele->offset &&
157            offset + length <= ele->offset+ele->length) {
158            return true;
159        }
160        ele = ele->next;
161    }
162    return false;
163}
164*/
165
166
167
168static errval_t debug_register(struct devq* q, struct capref cap,
169                               regionid_t rid)
170{
171    errval_t err;
172    struct debug_q* que = (struct debug_q*) q;
173    DEBUG("Register \n");
174    struct frame_identity id;
175
176    err = frame_identify(cap, &id);
177    if (err_is_fail(err)) {
178        return err;
179    }
180
181    // queue of regions is empty
182    if (que->regions == NULL) {
183        // add the reigon
184        err = que->q->f.reg(que->q, cap, rid);
185        if (err_is_fail(err)) {
186            return err;
187        }
188
189        que->regions = slab_alloc(&que->alloc_list);
190        assert(que->regions != NULL);
191
192        que->regions->rid = rid;
193        que->regions->length = id.bytes;
194        que->regions->not_consistent = false;
195        que->regions->next = NULL;
196        // add the whole regions as a buffer
197        que->regions->buffers = slab_alloc(&que->alloc);
198        assert(que->regions->buffers != NULL);
199
200        memset(que->regions->buffers, 0, sizeof(que->regions->buffers));
201        que->regions->buffers->offset = 0;
202        que->regions->buffers->length = id.bytes;
203        que->regions->buffers->next = NULL;
204        DEBUG("Register rid=%"PRIu32" size=%"PRIu64" \n", rid,
205              id.bytes);
206        return SYS_ERR_OK;
207    }
208
209    struct memory_list* ele = que->regions;
210    while (ele->next != NULL) {
211        ele = ele->next;
212    }
213
214    err = que->q->f.reg(que->q, cap, rid);
215    if (err_is_fail(err)) {
216        return err;
217    }
218
219    // add the reigon
220    ele->next = slab_alloc(&que->alloc_list);
221    assert(ele->next != NULL);
222
223    ele = ele->next;
224    ele->rid = rid;
225    ele->next = NULL;
226    ele->length = id.bytes;
227    ele->not_consistent = false;
228    // add the whole regions as a buffer
229    ele->buffers = slab_alloc(&que->alloc);
230    assert(ele->buffers != NULL);
231
232    memset(ele->buffers, 0, sizeof(ele->buffers));
233    ele->buffers->offset = 0;
234    ele->buffers->length = id.bytes;
235    ele->buffers->next = NULL;
236    DEBUG("Register rid=%"PRIu32" size=%"PRIu64" \n", rid,
237          id.bytes);
238
239    return SYS_ERR_OK;
240}
241
242static errval_t debug_deregister(struct devq* q, regionid_t rid)
243{
244    DEBUG("Deregister \n");
245    struct debug_q* que = (struct debug_q*) q;
246    errval_t err;
247
248    struct memory_list* ele = que->regions;
249    if (ele == NULL) {
250        return DEVQ_ERR_INVALID_REGION_ID;
251    }
252
253    // remove head
254    if (ele->rid == rid) {
255        // there should only be a single element in the list
256        // i.e. the whole region
257        if (ele->buffers->offset == 0 &&
258            ele->buffers->length == ele->length &&
259            ele->buffers->next == NULL) {
260
261            err = que->q->f.dereg(que->q, rid);
262            if (err_is_fail(err)) {
263                return err;
264            }
265            que->regions = ele->next;
266
267            DEBUG("removed region rid=%"PRIu32" size=%"PRIu64" \n", rid,
268                  ele->length);
269
270            slab_free(&que->alloc, ele->buffers);
271            slab_free(&que->alloc_list, ele);
272
273            return SYS_ERR_OK;
274        } else {
275
276            DEBUG("Destroy error rid=%d offset=%"PRIu64" length=%"PRIu64" "
277                       "should be offset=0 length=%"PRIu64"\n",
278                       ele->rid, ele->buffers->offset,
279                       ele->buffers->length, ele->length);
280            dump_list(ele);
281            return DEVQ_ERR_REGION_DESTROY;
282        }
283    }
284
285    while (ele->next != NULL) {
286        if (ele->next->rid == rid) {
287            if (ele->next->buffers->offset == 0 &&
288                ele->next->buffers->length == ele->next->length &&
289                ele->next->buffers->next == NULL) {
290
291                err = que->q->f.dereg(que->q, rid);
292                if (err_is_fail(err)) {
293                    return err;
294                }
295                // remove from queue
296                struct memory_list* next = ele->next;
297                ele->next = ele->next->next;
298
299                DEBUG("removed region rid=%"PRIu32" size=%"PRIu64" \n", rid,
300                      next->length);
301
302                slab_free(&que->alloc, next->buffers);
303                slab_free(&que->alloc_list, next);
304
305                return SYS_ERR_OK;
306            } else {
307                DEBUG("Destroy error rid=%d offset=%"PRIu64" length=%"PRIu64" "
308                       "should be offset=0 length=%"PRIu64"\n",
309                       ele->next->rid, ele->next->buffers->offset,
310                       ele->next->buffers->length, ele->next->length);
311
312                dump_list(ele);
313                return DEVQ_ERR_REGION_DESTROY;
314            }
315        } else {
316            ele = ele->next;
317        }
318    }
319
320
321    return DEVQ_ERR_INVALID_REGION_ID;
322}
323
324
325static errval_t debug_control(struct devq* q, uint64_t cmd, uint64_t value,
326                              uint64_t* result)
327{
328    DEBUG("control \n");
329    struct debug_q* que = (struct debug_q*) q;
330    return que->q->f.ctrl(que->q, cmd, value, result);
331}
332
333
334static errval_t debug_notify(struct devq* q)
335{
336    DEBUG("notify \n");
337    struct debug_q* que = (struct debug_q*) q;
338    return que->q->f.notify(que->q);
339}
340
341
342// is b1 in bounds of b2?
343static bool buffer_in_bounds(genoffset_t offset_b1, genoffset_t len_b1,
344                             genoffset_t offset_b2, genoffset_t len_b2)
345{
346    return (offset_b1 >= offset_b2) && (len_b1 <= len_b2) &&
347           ((offset_b1 + len_b1) <= offset_b2 + len_b2);
348}
349
350// assumes that the buffer described by offset and length is contained
351// in the buffer that is given as a struct
352static void remove_split_buffer(struct debug_q* que,
353                                struct memory_list* region,
354                                struct memory_ele* buffer,
355                                genoffset_t offset,
356                                genoffset_t length)
357{
358    // split the buffer
359    // insert half before the buffer
360
361    DEBUG("enqueue offset=%"PRIu64" length=%"PRIu64" buf->offset=%lu "
362          "buf->length %lu \n",
363          offset, length, buffer->offset, buffer->length);
364
365    // check if buffer at beginning of region
366    if (buffer->offset == offset) {
367        buffer->offset += length;
368        buffer->length -= length;
369
370        if (buffer->length == 0) {
371#ifdef DQ_ENABLE_HIST
372            add_to_history(que, offset, length, "enq cut of beginning remove");
373#endif
374            DEBUG("enqueue remove buffer from list\n");
375            // remove
376            if (buffer->prev != NULL) {
377                buffer->prev->next = buffer->next;
378            } else {
379                region->buffers = buffer->next;
380            }
381
382            if (buffer->next != NULL) {
383                buffer->next->prev = buffer->prev;
384            }
385            slab_free(&que->alloc, buffer);
386        } else {
387#ifdef DQ_ENABLE_HIST
388            add_to_history(que, offset, length, "enq cut of beginning");
389#endif
390        }
391
392        DEBUG("enqueue first cut off begining results in offset=%"PRIu64" "
393              "length=%"PRIu64"\n",
394              buffer->offset, buffer->length);
395        return;
396    }
397
398    // check if buffer at end of region
399    if ((buffer->offset+buffer->length) == (offset+length)) {
400        buffer->length -= length;
401
402        if (buffer->length == 0) {
403#ifdef DQ_ENABLE_HIST
404            add_to_history(que, offset, length, "enq cut of end remove");
405#endif
406            // remove
407            if (buffer->prev != NULL) {
408                buffer->prev = buffer->next;
409            }
410
411            if (buffer->next != NULL) {
412                buffer->next->prev = buffer->prev;
413            }
414            slab_free(&que->alloc, buffer);
415        } else {
416#ifdef DQ_ENABLE_HIST
417            add_to_history(que, offset, length, "enq cut of end");
418#endif
419        }
420
421        DEBUG("enqueue first cut off end results in offset=%"PRIu64" "
422              "length=%"PRIu64"\n",
423              buffer->offset, buffer->length);
424        return;
425    }
426
427    // now if this did not work need to split buffer that contains the
428    // enqueued buffer into two buffers (might also result only in one)
429
430    // inset half before buffer
431    genoffset_t old_len = buffer->length;
432
433    buffer->length = offset - buffer->offset;
434
435    struct memory_ele* after = NULL;
436    after = slab_alloc(&que->alloc);
437    assert(after != NULL);
438
439    memset(after, 0, sizeof(after));
440    after->offset = buffer->offset + buffer->length + length;
441    after->length = old_len - buffer->length - length;
442
443    // insert after buffer
444    after->prev = buffer;
445    after->next = buffer->next;
446
447    if (buffer->next != NULL) {
448        buffer->next->prev = after;
449    }
450
451    buffer->next = after;
452
453#ifdef DQ_ENABLE_HIST
454    add_to_history(que, offset, length, "enq split buffer");
455#endif
456
457    DEBUG("Split buffer length=%lu to "
458          "offset=%"PRIu64" length=%"PRIu64" and "
459          "offset=%lu length=%lu \n",
460          old_len,
461          buffer->offset, buffer->length,
462          after->offset, after->length);
463
464}
465
466/*
467 * Inserts a buffer either before or after an existing buffer into the queue
468 * Checks for merges of prev/next buffer in the queue
469 */
470static void insert_merge_buffer(struct debug_q* que,
471                                struct memory_list* region,
472                                struct memory_ele* buffer,
473                                genoffset_t offset,
474                                genoffset_t length)
475{
476    assert(buffer != NULL);
477    assert(region != NULL);
478
479    if (offset >= buffer->offset+buffer->length) {// insert after
480        // buffer is on lower boundary
481        //
482        if (buffer->offset+length == offset) {
483            buffer->length += length;
484            DEBUG("dequeue merge after "
485                  "offset=%"PRIu64" length=%"PRIu64" to offset=%"PRIu64" "
486                  "length=%"PRIu64"\n",
487                  offset, length, buffer->offset, buffer->length);
488            // check other boundary for merge
489            if (buffer->next != NULL &&
490                (buffer->offset + buffer->length == buffer->next->offset)) {
491                buffer->length += buffer->next->length;
492                struct memory_ele* next = buffer->next;
493                if (buffer->next->next != NULL) {
494                    buffer->next = buffer->next->next;
495                    buffer->next->next->prev = buffer;
496                }
497
498                DEBUG("dequeue merge after more offset=%"PRIu64" "
499                      "length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
500                      next->offset, next->length,
501                      buffer->offset, buffer->length);
502#ifdef DQ_ENABLE_HIST
503                add_to_history(que, offset, length, "deq insert after"
504                               " on lower boundary and merge");
505#endif
506                slab_free(&que->alloc, next);
507            } else {
508#ifdef DQ_ENABLE_HIST
509                add_to_history(que, offset, length, "deq insert after on lower boundary");
510#endif
511            }
512        } else {
513            // check higher boundary
514            if (buffer->next != NULL &&
515                buffer->next->offset == offset+length) {
516
517                buffer->next->offset = offset;
518                buffer->next->length += length;
519
520                DEBUG("dequeue merge after more offset=%"PRIu64" "
521                      "length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
522                      offset, length,
523                      buffer->next->offset, buffer->next->length);
524
525#ifdef DQ_ENABLE_HIST
526                add_to_history(que, offset, length, "deq insert after"
527                               " on higer boundary");
528#endif
529            } else {
530                // buffer->next can be null and the newly inserted buffer
531                // is the inserted at the end -> check boundary
532                if (buffer->next == NULL &&
533                    buffer->offset + buffer->length == offset) {
534
535                    buffer->length += length;
536
537#ifdef DQ_ENABLE_HIST
538                    add_to_history(que, offset, length, "deq insert after"
539                                   " on higer boundary end");
540#endif
541                    DEBUG("dequeue insert after merged offset=%"PRIu64" "
542                          "length=%"PRIu64" "
543                          "to offset=%"PRIu64" length=%"PRIu64" \n",
544                          offset, length, buffer->offset, buffer->length);
545                } else {
546                    // insert in between
547                    struct memory_ele* ele = slab_alloc(&que->alloc);
548                    assert(ele != NULL);
549
550                    ele->offset = offset;
551                    ele->length = length;
552                    ele->next = buffer->next;
553                    ele->prev = buffer;
554
555                    if (buffer->next != NULL) {
556                        buffer->next->prev = ele;
557                    }
558
559                    buffer->next = ele;
560
561#ifdef DQ_ENABLE_HIST
562                    add_to_history(que, offset, length, "deq insert after"
563                                   " in between");
564#endif
565                    DEBUG("dequeue insert after offset=%"PRIu64" length=%"PRIu64" "
566                          "after offset=%"PRIu64" length=%"PRIu64" \n",
567                          offset, length, buffer->offset, buffer->length);
568                }
569            }
570        }
571    } else { // insert before buffer
572        // buffer is on lower boundary
573        if (buffer->offset == offset+length) {
574            buffer->length += length;
575            buffer->offset = offset;
576
577            // check other boundary
578            if (buffer->prev != NULL &&
579                (buffer->prev->offset+ buffer->prev->length ==
580                buffer->offset)) {
581                struct memory_ele* prev = buffer->prev;
582                prev->length += buffer->length;
583                prev->next = buffer->next;
584
585                if (buffer->next != NULL) {
586                    buffer->next->prev = prev;
587                }
588
589                slab_free(&que->alloc, buffer);
590
591#ifdef DQ_ENABLE_HIST
592                add_to_history(que, offset, length, "deq insert buffer"
593                               " before lower boundary merge");
594#endif
595                DEBUG("dequeue merge before more offset=%"PRIu64" "
596                      "length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
597                      offset, length, prev->offset, prev->length);
598            } else {
599#ifdef DQ_ENABLE_HIST
600                add_to_history(que, offset, length, "deq insert buffer"
601                               " before lower boundary");
602#endif
603            }
604        } else {
605            // check lower boundary
606            if (buffer->prev != NULL &&
607                (buffer->prev->offset+ buffer->prev->length ==
608                offset)) {
609                if (length == 0) {
610                    printf("Length is 0 \n");
611                    buffer->prev->length += 2048;
612                }
613
614                buffer->prev->length += length;
615
616#ifdef DQ_ENABLE_HIST
617                add_to_history(que, offset, length, "deq insert buffer"
618                               " before prev lower boundary merge");
619#endif
620                DEBUG("dequeue merge before more offset=%"PRIu64" "
621                      "length=%"PRIu64" to offset=%"PRIu64" length=%"PRIu64" \n ",
622                      offset, length, buffer->prev->offset, buffer->prev->length);
623            } else { // insert in between
624
625                // insert in between
626                struct memory_ele* ele = slab_alloc(&que->alloc);
627                assert(ele != NULL);
628
629                memset(ele, 0, sizeof(ele));
630                ele->offset = offset;
631                ele->length = length;
632                ele->next = buffer;
633                ele->prev = buffer->prev;
634
635                if (buffer->prev != NULL) {
636                    buffer->prev->next = ele;
637                } else {
638                    region->buffers = ele;
639                }
640
641                buffer->prev = ele;
642
643#ifdef DQ_ENABLE_HIST
644                add_to_history(que, offset, length, "deq insert buffer"
645                               " before in between");
646#endif
647                DEBUG("dequeue insert before offset=%"PRIu64" length=%"PRIu64" "
648                      "next is offset=%"PRIu64" length=%"PRIu64" \n",
649                      offset, length,
650                      buffer->offset, buffer->length);
651            }
652        }
653    }
654}
655
656static errval_t find_region(struct debug_q* que, struct memory_list** list,
657                            regionid_t rid)
658{
659    // find region
660    struct memory_list* region = que->regions;
661
662    while (region != NULL) {
663        if (region->rid == rid) {
664            break;
665        }
666        region = region->next;
667    }
668
669    // check if we found the region
670    if (region == NULL) {
671        return DEVQ_ERR_INVALID_REGION_ID;
672    }
673
674    *list = region;
675    return SYS_ERR_OK;
676}
677
678static errval_t debug_enqueue(struct devq* q, regionid_t rid,
679                              genoffset_t offset, genoffset_t length,
680                              genoffset_t valid_data, genoffset_t valid_length,
681                              uint64_t flags)
682{
683    assert(length > 0);
684    DEBUG("enqueue offset %"PRIu64" \n", offset);
685    errval_t err;
686    struct debug_q* que = (struct debug_q*) q;
687
688    // find region
689    struct memory_list* region = NULL;
690
691    err = find_region(que, &region, rid);
692    if (err_is_fail(err)){
693        return err;
694    }
695
696    //check_consistency(region);
697
698    // find the buffer
699    struct memory_ele* buffer = region->buffers;
700
701    if (region->buffers == NULL) {
702        return DEVQ_ERR_BUFFER_ALREADY_IN_USE;
703    }
704
705    // the only buffer
706    if (buffer->next == NULL) {
707        if (buffer_in_bounds(offset, length,
708                             buffer->offset, buffer->length)) {
709            err = que->q->f.enq(que->q, rid, offset, length, valid_data,
710                                valid_length, flags);
711            if (err_is_fail(err)) {
712                return err;
713            }
714
715            remove_split_buffer(que, region, buffer, offset, length);
716            return SYS_ERR_OK;
717        } else {
718            printf("Bounds check failed only buffer offset=%lu length=%lu "
719                  " buf->offset=%lu buf->len=%lu\n", offset, length,
720                  buffer->offset, buffer->length);
721#ifdef DQ_ENABLE_HIST
722            dump_history(que);
723#endif
724            dump_list(region);
725            return DEVQ_ERR_INVALID_BUFFER_ARGS;
726        }
727    }
728
729
730    // more than one buffer
731    while (buffer != NULL) {
732        if (buffer_in_bounds(offset, length,
733                             buffer->offset, buffer->length)){
734            err = que->q->f.enq(que->q, rid, offset, length, valid_data,
735                                valid_length, flags);
736            if (err_is_fail(err)) {
737                return err;
738            }
739
740            remove_split_buffer(que, region, buffer, offset, length);
741            return SYS_ERR_OK;
742        }
743        buffer = buffer->next;
744    }
745
746    printf("Did not find region offset=%ld length=%ld \n", offset, length);
747#ifdef DQ_ENABLE_HIST
748    dump_history(que);
749#endif
750    dump_list(region);
751
752    return DEVQ_ERR_INVALID_BUFFER_ARGS;
753}
754
755static errval_t debug_dequeue(struct devq* q, regionid_t* rid, genoffset_t* offset,
756                              genoffset_t* length, genoffset_t* valid_data,
757                              genoffset_t* valid_length, uint64_t* flags)
758{
759    errval_t err;
760    struct debug_q* que = (struct debug_q*) q;
761    assert(que->q->f.deq != NULL);
762    err = que->q->f.deq(que->q, rid, offset, length, valid_data,
763                        valid_length, flags);
764    if (err_is_fail(err)) {
765        return err;
766    }
767    DEBUG("dequeued offset=%lu \n", *offset);
768
769    struct memory_list* region = NULL;
770
771    err = find_region(que, &region, *rid);
772    if (err_is_fail(err)){
773        // region ids are checked bythe devq library, if we do not find
774        // the region id when dequeueing here we do not have a consistant
775        // view of two endpoints
776        //
777        // Add region
778        if (que->regions == NULL) {
779            printf("Adding region frirst %lu len \n", *offset + *length);
780
781            que->regions = slab_alloc(&que->alloc_list);
782            assert(que->regions != NULL);
783
784            que->regions->rid = *rid;
785            que->regions->not_consistent = true;
786            // region is at least offset + length
787            que->regions->length = *offset + *length;
788            que->regions->next = NULL;
789            // add the whole regions as a buffer
790            que->regions->buffers = slab_alloc(&que->alloc);
791            assert(que->regions->buffers != NULL);
792
793            memset(que->regions->buffers, 0, sizeof(que->regions->buffers));
794            que->regions->buffers->offset = 0;
795            que->regions->buffers->length = *offset + *length;
796            que->regions->buffers->next = NULL;
797            return SYS_ERR_OK;
798        }
799
800        struct memory_list* ele = que->regions;
801        while (ele->next != NULL) {
802            ele = ele->next;
803        }
804
805        printf("Adding region second %lu len \n", *offset + *length);
806        // add the reigon
807        ele->next = slab_alloc(&que->alloc_list);
808        assert(ele->next != NULL);
809
810        memset(que->regions->buffers, 0, sizeof(ele->next));
811        ele = ele->next;
812
813        ele->rid = *rid;
814        ele->next = NULL;
815        ele->not_consistent = true;
816        ele->length = *offset + *length;
817        // add the whole regions as a buffer
818        ele->buffers = slab_alloc(&que->alloc);
819        assert(ele->buffers != NULL);
820
821        memset(ele->buffers, 0, sizeof(ele->buffers));
822        ele->buffers->offset = 0;
823        ele->buffers->length = *offset + *length;
824        ele->buffers->next = NULL;
825        return SYS_ERR_OK;
826    }
827
828    if (region->not_consistent) {
829        if ((*offset + *length) > region->length) {
830            region->length = *offset + *length;
831        }
832    }
833
834    //check_consistency(region);
835
836    // find the buffer
837    struct memory_ele* buffer = region->buffers;
838    if (buffer == NULL) {
839        region->buffers = slab_alloc(&que->alloc);
840        assert(region->buffers != NULL);
841
842        region->buffers->offset = *offset;
843        region->buffers->length = *length;
844        region->buffers->next = NULL;
845        region->buffers->prev = NULL;
846        return SYS_ERR_OK;
847    }
848
849    if (buffer->next == NULL) {
850        if (!buffer_in_bounds(*offset, *length, buffer->offset,
851                              buffer->length)) {
852            insert_merge_buffer(que, region, buffer, *offset, *length);
853            return SYS_ERR_OK;
854        } else {
855            return DEVQ_ERR_BUFFER_NOT_IN_USE;
856        }
857    }
858
859
860    while (buffer->next != NULL) {
861        if (*offset >= buffer->offset) {
862            buffer = buffer->next;
863        } else {
864            if (!buffer_in_bounds(*offset, *length, buffer->offset,
865                buffer->length)) {
866                insert_merge_buffer(que, region, buffer, *offset, *length);
867                return SYS_ERR_OK;
868            } else {
869                return DEVQ_ERR_BUFFER_NOT_IN_USE;
870            }
871        }
872    }
873
874    // insert after the last buffer
875    if (!buffer_in_bounds(*offset, *length, buffer->offset,
876        buffer->length)) {
877        insert_merge_buffer(que, region, buffer, *offset, *length);
878        return SYS_ERR_OK;
879    }
880
881    return DEVQ_ERR_BUFFER_NOT_IN_USE;
882}
883
884static errval_t debug_destroy(struct devq* devq)
885{
886    // TODO cleanup
887    return SYS_ERR_OK;
888}
889
890/**
891 * Public functions
892 *
893 */
894
895errval_t debug_create(struct debug_q** q, struct devq* other_q)
896{
897    errval_t err;
898    struct debug_q* que;
899    que = calloc(1, sizeof(struct debug_q));
900    assert(que);
901
902    slab_init(&que->alloc, sizeof(struct memory_ele),
903              slab_default_refill);
904
905    slab_init(&que->alloc_list, sizeof(struct memory_list),
906              slab_default_refill);
907
908    que->q = other_q;
909    err = devq_init(&que->my_q, false);
910    if (err_is_fail(err)) {
911        return err;
912    }
913
914    que->my_q.f.reg = debug_register;
915    que->my_q.f.dereg = debug_deregister;
916    que->my_q.f.ctrl = debug_control;
917    que->my_q.f.notify = debug_notify;
918    que->my_q.f.enq = debug_enqueue;
919    que->my_q.f.deq = debug_dequeue;
920    que->my_q.f.destroy = debug_destroy;
921    *q = que;
922    return SYS_ERR_OK;
923}
924
925errval_t debug_dump_region(struct debug_q* que, regionid_t rid)
926{
927    errval_t err;
928    // find region
929    struct memory_list* region = NULL;
930
931    err = find_region(que, &region, rid);
932    if (err_is_fail(err)){
933        return err;
934    }
935
936    dump_list(region);
937    return SYS_ERR_OK;
938}
939
940
941void debug_dump_history(struct debug_q* q)
942{
943#ifdef DQ_ENABLE_HIST
944    dump_history(q);
945#endif
946}
947
948errval_t debug_add_region(struct debug_q* q, struct capref cap,
949                         regionid_t rid)
950{
951    return devq_add_region((struct devq*) q, cap, rid);
952}
953
954errval_t debug_remove_region(struct debug_q* q, regionid_t rid)
955{
956    return devq_remove_region((struct devq*) q, rid);
957}
958