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, ®ion, 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, ®ion, *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, ®ion, 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