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