alloc.c (16710B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: alloc.c 8 * Purpose: Defines sal routines for memory allocation 9 */ 10 11 #ifdef LINUX_SAL_DMA_ALLOC_OVERRIDE 12 /* Keep local functions, but use a different name */ 13 #define sal_dma_alloc sal_sim_dma_alloc 14 #define sal_dma_free sal_sim_dma_free 15 #endif 16 17 #include <sys/types.h> 18 #ifdef PTRS_ARE_64BITS 19 #include <unistd.h> 20 #include <sys/mman.h> 21 #endif 22 #include <stdlib.h> 23 #include <assert.h> 24 25 #include <sal/types.h> 26 #include <sal/core/thread.h> 27 #include <sal/core/memlog.h> 28 29 #ifdef MEMORY_MEASUREMENT_DIAGNOSTICS 30 #include <shared/mem_measure_tool.h> 31 #endif 32 33 #ifndef USE_EXTERNAL_MEM_CHECKING 34 /* { */ 35 #define USE_EXTERNAL_MEM_CHECKING 0 36 /* } */ 37 #endif 38 #if USE_EXTERNAL_MEM_CHECKING 39 /* { */ 40 #define EXT_DEBUG_ALLOC(_sz) do { return malloc(_sz); } while(0) 41 #define EXT_DEBUG_FREE(_addr) do { free(_addr); return; } while(0) 42 /* } */ 43 #else 44 /* { */ 45 #define EXT_DEBUG_ALLOC(_sz) 46 #define EXT_DEBUG_FREE(_addr) 47 /* } */ 48 #endif 49 50 #ifndef AGGRESSIVE_ALLOC_DEBUG_TESTING 51 /* { */ 52 #define AGGRESSIVE_ALLOC_DEBUG_TESTING 0 53 /* } */ 54 #endif 55 #if AGGRESSIVE_ALLOC_DEBUG_TESTING 56 /* { */ 57 #if USE_EXTERNAL_MEM_CHECKING 58 /* { */ 59 #error "USE_EXTERNAL_MEM_CHECKING and AGGRESSIVE_ALLOC_DEBUG_TESTING can\'t be set both." 60 /* } */ 61 #endif 62 #ifndef AGGRESSIVE_ALLOC_DEBUG_TESTING_KEEP_ORDER 63 /* { */ 64 /* The allocations stored in array. 65 * When freeing allocation in the middle of the array, 66 * the last entry in the array replace it. 67 * if this flags is set, all the entries next to the free allocation will be pushed down, 68 * and hence, the order will be kept. 69 */ 70 #define AGGRESSIVE_ALLOC_DEBUG_TESTING_KEEP_ORDER 0 71 /* } */ 72 #endif 73 #include "alloc_debug.h" 74 #define AGGR_DEBUG_ALLOC(_p, _sz, _s) sal_alloc_debug_alloc(_p, _sz, _s) 75 #define AGGR_DEBUG_FREE(_addr) sal_alloc_debug_free(_addr) 76 #define AGGR_DEBUG_PRINT_BAD_ADDR(_addr) sal_alloc_debug_print_bad_addr(_addr) 77 /* } */ 78 #else 79 /* { */ 80 #define AGGR_DEBUG_ALLOC(_p, _sz, _s) 81 #define AGGR_DEBUG_FREE(_addr) 82 #define AGGR_DEBUG_PRINT_BAD_ADDR(addr) 83 /* } */ 84 #endif /* AGGRESSIVE_ALLOC_DEBUG_TESTING */ 85 86 87 /* To do: use real data segment limits for bad pointer detection */ 88 #define BAD_PTR(p) \ 89 (PTR_TO_UINTPTR(p) < 0x1000UL || \ 90 PTR_TO_UINTPTR(p) > ~0xfffUL) 91 #define CORRUPT(p) \ 92 (p[-1] != 0xaaaaaaaa || \ 93 p[p[-2]] != 0xbbbbbbbb) 94 #define FREED_PTR(p) ((p[-1] == 0xcccccccc) && (p[p[-2]] == 0xdddddddd)) 95 96 static unsigned long sal_alloc_bytes; 97 static unsigned long sal_alloc_calls; 98 static unsigned long sal_free_bytes; 99 static unsigned long sal_free_calls; 100 101 static unsigned long sal_alloc_bytes_main_thr; 102 static unsigned long sal_free_bytes_main_thr; 103 104 #ifdef BROADCOM_DEBUG 105 /* { */ 106 #ifdef INCLUDE_BCM_SAL_PROFILE 107 /* { */ 108 static unsigned int _sal_alloc_max = 0 ; 109 static unsigned int _sal_alloc_curr = 0 ; 110 111 #define SAL_ALLOC_RESOURCE_USAGE_INCR(a_curr, a_max, a_size, ilock) \ 112 a_curr += (a_size); \ 113 a_max = ((a_curr) > (a_max)) ? (a_curr) : (a_max) 114 115 #define SAL_ALLOC_RESOURCE_USAGE_DECR(a_curr, a_size, ilock) \ 116 a_curr -= (a_size) \ 117 118 /* 119 * Function: 120 * sal_alloc_resource_usage_get 121 * Purpose: 122 * Provides Current/Maximum memory allocation. 123 * Parameters: 124 * alloc_curr - Current memory usage. 125 * alloc_max - Memory usage high water mark 126 */ 127 128 void 129 sal_alloc_resource_usage_get(uint32 *alloc_curr, uint32 *alloc_max) 130 { 131 if (alloc_curr != NULL) { 132 *alloc_curr = _sal_alloc_curr; 133 } 134 if (alloc_max != NULL) { 135 *alloc_max = _sal_alloc_max; 136 } 137 } 138 static unsigned int _sal_dma_alloc_max; 139 static unsigned int _sal_dma_alloc_curr; 140 141 #define SAL_DMA_ALLOC_RESOURCE_USAGE_INCR(a_curr, a_max, a_size, ilock) \ 142 a_curr += (a_size); \ 143 a_max = ((a_curr) > (a_max)) ? (a_curr) : (a_max) 144 145 #define SAL_DMA_ALLOC_RESOURCE_USAGE_DECR(a_curr, a_size, ilock) \ 146 a_curr -= (a_size) 147 148 /* 149 * Function: 150 * sal_dma_alloc_resource_usage_get 151 * Purpose: 152 * Provides Current/Maximum memory allocation. 153 * Parameters: 154 * alloc_curr - Current memory usage. 155 * alloc_max - Memory usage high water mark 156 */ 157 158 void 159 sal_dma_alloc_resource_usage_get(uint32 *alloc_curr, uint32 *alloc_max) 160 { 161 if (alloc_curr != NULL) { 162 *alloc_curr = _sal_dma_alloc_curr; 163 } 164 if (alloc_max != NULL) { 165 *alloc_max = _sal_dma_alloc_max; 166 } 167 } 168 /* } */ 169 #endif 170 /* 171 * Function: 172 * sal_alloc_stat 173 * Purpose: 174 * Dump the current allocations 175 * Parameters: 176 * param - integer used to change behavior. 177 * Notes: 178 * If the parameter is non-zero, the routine will not 179 * display successive entries with the same description. 180 */ 181 void 182 sal_alloc_stat(void *param) 183 { 184 } 185 /* } */ 186 #endif /* BROADCOM_DEBUG */ 187 188 /** 189 * \brief 190 * Get the main thread allocated and freed bytes counters. 191 * \param [out] alloc_bytes_count - 192 * Pointer to alloc bytes counter storage. 193 * \param [out] free_bytes_count - 194 * Pointer to free bytes counter storage. 195 * \return 196 * (void) 197 * \remark 198 * * None 199 * \see 200 * * None 201 */ 202 void sal_get_alloc_counters_main_thr(unsigned long *alloc_bytes_count,unsigned long *free_bytes_count) 203 { 204 *alloc_bytes_count = sal_alloc_bytes_main_thr; 205 *free_bytes_count = sal_free_bytes_main_thr; 206 } 207 208 /** 209 * \brief 210 * Offsets the main thread allocated and freed bytes counters 211 * \param [out] alloc_bytes_count_offset - 212 * Value that is substracted from the alloc bytes counter. 213 * \param [out] free_bytes_count_offset - 214 * Value that is substracted from the free bytes counter. 215 * \return 216 * (void) 217 * \remark 218 * * Used by sw state internals to offset the sal_alloc and sal_free counters 219 * \see 220 * * dnxc_sw_state_alloc_plain 221 */ 222 void sal_set_alloc_counters_offset_main_thr(unsigned long alloc_bytes_count_offset, unsigned long free_bytes_count_offset) 223 { 224 sal_alloc_bytes_main_thr -= alloc_bytes_count_offset; 225 sal_free_bytes_main_thr -= free_bytes_count_offset; 226 } 227 228 /** 229 * \brief 230 * Get the allocated and freed bytes counters. 231 * Pointer to alloc bytes counter storage. 232 * \param [out] free_bytes_count - 233 * Pointer to free bytes counter storage. 234 * \return 235 * (void) 236 * \remark 237 * * None 238 * \see 239 * * None 240 */ 241 void sal_get_alloc_counters(unsigned long *alloc_bytes_count,unsigned long *free_bytes_count) 242 { 243 *alloc_bytes_count = sal_alloc_bytes; 244 *free_bytes_count = sal_free_bytes; 245 } 246 247 /** 248 * \brief 249 * Offsets the allocated and freed bytes counters. 250 * \param [out] alloc_bytes_count_offset - 251 * Value that is substracted from the alloc bytes counter. 252 * \param [out] free_bytes_count_offset - 253 * Value that is substracted from the free bytes counter. 254 * \return 255 * (void) 256 * \remark 257 * * Used by sw state internals to offset the sal_alloc and sal_free counters 258 * \see 259 * * dnxc_sw_state_alloc_plain 260 */ 261 void sal_set_alloc_counters_offset(unsigned long alloc_bytes_count_offset, unsigned long free_bytes_count_offset) 262 { 263 sal_alloc_bytes -= alloc_bytes_count_offset; 264 sal_free_bytes -= free_bytes_count_offset; 265 } 266 267 /* 268 * Function: 269 * sal_alloc 270 * Purpose: 271 * Allocate general purpose system memory. 272 * Parameters: 273 * sz - size of memory block to allocate. 274 * s - optional user description of memory block for debugging. 275 * Returns: 276 * Pointer to memory block 277 * Notes: 278 * Memory allocated by this routine is not guaranteed to be safe 279 * for hardware DMA read/write. 280 */ 281 282 void * 283 sal_alloc(unsigned int sz, char *s) 284 { 285 unsigned int orig_sz, alloc_sz; 286 uint32 *p; 287 288 #ifdef MEMORY_MEASUREMENT_DIAGNOSTICS 289 uint32 idx; 290 #endif 291 292 EXT_DEBUG_ALLOC(sz); 293 294 /* 295 * Round up size to accommodate corruption detection sentinels. 296 * Place sentinels at the beginning and end of the data area to 297 * detect memory corruption. These are verified on free. 298 */ 299 300 orig_sz = sz; 301 302 sz = (sz + 3) & ~3; 303 304 /* Check for wrap caused by bad input */ 305 alloc_sz = sz + 12; 306 if (alloc_sz < orig_sz) { 307 return NULL; 308 } 309 310 sal_alloc_calls += 1; 311 312 if ((p = malloc(alloc_sz)) == 0) { 313 return p; 314 } 315 316 assert(UINTPTR_TO_PTR(PTR_TO_UINTPTR(p)) == p); 317 318 if (sal_thread_self() == sal_thread_main_get()) 319 { 320 sal_alloc_bytes_main_thr += sz; 321 } 322 323 sal_alloc_bytes += sz; 324 325 p[0] = sz / 4; 326 p[1] = 0xaaaaaaaa; 327 p[2 + sz / 4] = 0xbbbbbbbb; 328 329 #ifdef MEMORY_MEASUREMENT_DIAGNOSTICS 330 MEMORY_MEASUREMENT_INITIALIZE; 331 for(idx = 0;idx < memory_measurement_tool.count;idx++) { 332 if(memory_measurement_tool.elements[idx].is_active && (memory_measurement_tool.elements[idx].thread_id == sal_thread_self())) { 333 memory_measurement_tool.elements[idx].sal_size += sz; 334 } 335 } 336 #endif 337 338 #ifdef BROADCOM_DEBUG 339 /* { */ 340 #ifdef INCLUDE_BCM_SAL_PROFILE 341 /* { */ 342 SAL_ALLOC_RESOURCE_USAGE_INCR( 343 _sal_alloc_curr, 344 _sal_alloc_max, 345 (sz), 346 ilock); 347 348 /* } */ 349 #endif 350 /* } */ 351 #endif /* BROADCOM_DEBUG */ 352 353 AGGR_DEBUG_ALLOC(p, sz, s); 354 355 MEMLOG_ALLOC("sal_alloc", (void *)&p[0], orig_sz, s); 356 357 return (void *) &p[2]; 358 } 359 360 /* 361 * Function: 362 * sal_free 363 * Purpose: 364 * Free memory block allocate by sal_alloc 365 * Parameters: 366 * addr - Address returned by sal_alloc 367 */ 368 369 void 370 sal_free(void *addr) 371 { 372 uint32 *p = (uint32 *)addr; 373 uint32 *ap = p; /* Originally Allocated Pointer */ 374 375 #ifdef MEMORY_MEASUREMENT_DIAGNOSTICS 376 uint32 idx; 377 #endif 378 379 EXT_DEBUG_FREE(addr); 380 381 /* 382 * Verify sentinels on free. If this assertion fails, it means that 383 * memory corruption was detected. 384 */ 385 386 #ifdef SAL_FREE_NULL_IGNORE 387 /* { */ 388 if (addr == NULL) 389 { 390 return; 391 } 392 /* } */ 393 #endif 394 395 AGGR_DEBUG_FREE(addr); 396 397 if (BAD_PTR(p) || FREED_PTR(p) || CORRUPT(p)) { 398 AGGR_DEBUG_PRINT_BAD_ADDR(addr); 399 assert(!BAD_PTR(p)); /* Use macro to beautify assert message */ 400 assert(!FREED_PTR(p)); /* Detect double freed memory */ 401 assert(!CORRUPT(p)); /* Use macro to beautify assert message */ 402 } 403 404 /* Adjust for Corruption detection Sentinels */ 405 ap--; 406 ap--; 407 408 if (sal_thread_self() == sal_thread_main_get()) 409 { 410 sal_free_bytes_main_thr += ap[0] * 4; 411 } 412 413 sal_free_calls += 1; 414 sal_free_bytes += ap[0] * 4; 415 416 #ifdef MEMORY_MEASUREMENT_DIAGNOSTICS 417 for(idx = 0;idx < memory_measurement_tool.count;idx++) { 418 if(memory_measurement_tool.elements[idx].is_active && (memory_measurement_tool.elements[idx].thread_id == sal_thread_self())) { 419 memory_measurement_tool.elements[idx].sal_size -= (ap[0] * 4); 420 } 421 } 422 #endif 423 424 #ifdef BROADCOM_DEBUG 425 /* { */ 426 #ifdef INCLUDE_BCM_SAL_PROFILE 427 /* { */ 428 SAL_ALLOC_RESOURCE_USAGE_DECR( 429 _sal_alloc_curr, 430 (ap[0] * 4), 431 ilock); 432 433 /* } */ 434 #endif 435 /* } */ 436 #endif /* BROADCOM_DEBUG */ 437 438 MEMLOG_FREE("sal_free", (void *)&p[-2]); 439 440 ap[1] = 0xcccccccc; /* Detect redundant frees */ 441 ap[2 + ap[0]] = 0xdddddddd; 442 /* coverity[address_free : FALSE] */ 443 free(ap); 444 } 445 446 /* 447 * Function: 448 * sal_dma_alloc 449 * Purpose: 450 * Allocate memory that can be DMA'd into/out of. 451 * Parameters: 452 * sz - number of bytes to allocate 453 * s - string associated with allocate 454 * Returns: 455 * Pointer to allocated memory or NULL if out of memory. 456 * Notes: 457 * Memory allocated by this routine is not guaranteed to be safe 458 * for hardware DMA read/write. This is for use only on sim platform. 459 */ 460 461 void * 462 sal_dma_alloc(size_t sz, char *s) 463 { 464 uint32 *p; 465 size_t new_sz; 466 #if defined(PTRS_ARE_64BITS) && defined(MAP_32BIT) 467 long pagesz = sysconf(_SC_PAGESIZE); 468 #endif 469 470 /* 471 * Round up size to accommodate corruption detection sentinels. 472 * Place sentinels at the beginning and end of the data area to 473 * detect memory corruption. These are verified on free. 474 */ 475 sz = (sz + 3) & ~3; 476 477 /* Add bytes for holding sentinals */ 478 new_sz = sz + 12; 479 480 #if defined(PTRS_ARE_64BITS) && defined(MAP_32BIT) 481 /* For 64 bit SDK simulation image use mmap with MAP_32BIT flag for 482 * allocation as we need allocated region to be addressable in 32bit 483 * address space. Normal malloc would return memory in 64 bit virtual 484 * address space. Also allign the size to a page boundary as mmap 485 * allocates memory in pages 486 */ 487 new_sz = (new_sz + (size_t)(pagesz-1)) & ~(pagesz-1); 488 p = mmap(NULL, 489 new_sz, 490 PROT_READ|PROT_WRITE, 491 MAP_ANONYMOUS|MAP_SHARED|MAP_32BIT, 492 -1, 493 0); 494 if (MAP_FAILED == p) { 495 return NULL; 496 } 497 #else 498 if ((p = malloc(new_sz)) == 0) { 499 return p; 500 } 501 #endif 502 503 assert(INT_TO_PTR(PTR_TO_INT(p)) == p); 504 505 p[0] = sz / 4; 506 p[1] = 0xaaaaaaaa; 507 p[2 + sz / 4] = 0xbbbbbbbb; 508 #ifdef BROADCOM_DEBUG 509 /* { */ 510 #ifdef INCLUDE_BCM_SAL_PROFILE 511 /* { */ 512 SAL_DMA_ALLOC_RESOURCE_USAGE_INCR( 513 _sal_dma_alloc_curr, 514 _sal_dma_alloc_max, 515 (sz), 516 ilock); 517 /* } */ 518 #endif 519 /* } */ 520 #endif /* BROADCOM_DEBUG */ 521 522 MEMLOG_ALLOC("sal_dma_alloc", &p[0], new_sz, s); 523 524 return (void *) &p[2]; 525 } 526 527 /* 528 * Function: 529 * sal_dma_free 530 * Purpose: 531 * Free memory allocated by sal_dma_alloc 532 * Parameters: 533 * addr - pointer to memory to free. 534 * Returns: 535 * Nothing. 536 */ 537 538 void 539 sal_dma_free(void *addr) 540 { 541 #if defined(PTRS_ARE_64BITS) && defined(MAP_32BIT) 542 int org_sz; 543 long pagesz = sysconf(_SC_PAGESIZE); 544 #endif 545 uint32 *p = (uint32 *)addr; 546 uint32 *ap = p; /* Originally Allocated Pointer */ 547 548 /* 549 * Verify sentinels on free. If this assertion fails, it means that 550 * memory corruption was detected. 551 */ 552 553 /* coverity[conditional (1): FALSE] */ 554 /* coverity[conditional (2): FALSE] */ 555 assert(!BAD_PTR(p)); /* Use macro to beautify assert message */ 556 /* Detect double freed memory */ 557 assert(!FREED_PTR(p)); 558 /* coverity[conditional (3): FALSE] */ 559 /* coverity[conditional (4): FALSE] */ 560 assert(!CORRUPT(p)); /* Use macro to beautify assert message */ 561 562 563 /* Adjust for Corruption detection Sentinels */ 564 ap--; 565 ap--; 566 567 #ifdef BROADCOM_DEBUG 568 /* { */ 569 #ifdef INCLUDE_BCM_SAL_PROFILE 570 /* { */ 571 SAL_DMA_ALLOC_RESOURCE_USAGE_DECR( 572 _sal_dma_alloc_curr, 573 (ap[0] * 4), 574 ilock); 575 /* } */ 576 #endif 577 /* } */ 578 #endif /* BROADCOM_DEBUG */ 579 580 MEMLOG_FREE("sal_dma_free", ap); 581 582 ap[1] = 0xcccccccc; /* Detect redundant frees */ 583 ap[2 + ap[0]] = 0xdddddddd; 584 #if defined(PTRS_ARE_64BITS) && defined(MAP_32BIT) 585 /* For 64 bit SDK simulation image use munmap as the allocation 586 * was done using mmap. Also re-adjust the size such that it is 587 * page alligned. 588 */ 589 org_sz = (ap[0] * 4) + 12; /* Add 12 for 3 sentinels */ 590 org_sz = (org_sz + (size_t)(pagesz-1)) & ~(pagesz-1); 591 munmap(ap, org_sz); 592 #else 593 /* coverity[address_free : FALSE] */ 594 free(ap); 595 #endif 596 } 597 598 /* 599 * Function: 600 * sal_dma_flush 601 * Purpose: 602 * Ensure modified cache is written out to memory. 603 * Parameters: 604 * addr - beginning of address region 605 * len - size of address region 606 * Notes: 607 * A region of memory should always be flushed before telling 608 * hardware to start a DMA read from that memory. 609 */ 610 611 void 612 sal_dma_flush(void *addr, int len) 613 { 614 COMPILER_REFERENCE(addr); 615 COMPILER_REFERENCE(len); 616 } 617 618 /* 619 * Function: 620 * sal_dma_inval 621 * Purpose: 622 * Ensure cache memory is discarded and not written out to memory. 623 * Parameters: 624 * addr - beginning of address region 625 * len - size of address region 626 * Notes: 627 * A region of memory should always be invalidated before telling 628 * hardware to start a DMA write into that memory. 629 */ 630 631 void 632 sal_dma_inval(void *addr, int len) 633 { 634 COMPILER_REFERENCE(addr); 635 COMPILER_REFERENCE(len); 636 } 637 638 /* 639 * Function: 640 * sal_dma_vtop 641 * Purpose: 642 * Convert a virtual memory address to physical. 643 * Parameters: 644 * addr - address to convert 645 * Returns: 646 * Physical address 647 */ 648 649 void * 650 sal_dma_vtop(void *addr) 651 { 652 return addr; 653 } 654 655 /* 656 * Function: 657 * sal_dma_ptov 658 * Purpose: 659 * Convert a physical memory address to virtual. 660 * Parameters: 661 * addr - address to convert 662 * Returns: 663 * Virtual address 664 */ 665 666 void * 667 sal_dma_ptov(void *addr) 668 { 669 return addr; 670 } 671 672 /* 673 * Function: 674 * sal_memory_check 675 * Purpose: 676 * Check an address in memory for existence and writability. 677 * Parameters: 678 * addr - address to check 679 * Returns: 680 * 0 if writable, 1 if not 681 * Notes: 682 * Should be written to catch SIGBUS and SIGSEGV. 683 * For now, just returns success. 684 */ 685 686 int 687 sal_memory_check(uint32 addr) 688 { 689 return 0; 690 }