iPXE
Data Structures | Defines | Functions | Variables
malloc.c File Reference

Dynamic memory allocation. More...

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <ipxe/io.h>
#include <ipxe/list.h>
#include <ipxe/init.h>
#include <ipxe/refcnt.h>
#include <ipxe/malloc.h>
#include <valgrind/memcheck.h>

Go to the source code of this file.

Data Structures

struct  memory_block
 A free block of memory. More...
struct  autosized_block
 A block of allocated memory complete with size information. More...

Defines

#define MIN_MEMBLOCK_SIZE   ( ( size_t ) ( 1 << ( fls ( sizeof ( struct memory_block ) - 1 ) ) ) )
#define NOWHERE   ( ( void * ) ~( ( intptr_t ) 0 ) )
 Address for zero-length memory blocks.
#define HEAP_SIZE   ( 512 * 1024 )
 Heap size.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static LIST_HEAD (free_blocks)
 List of free memory blocks.
static void valgrind_make_blocks_defined (void)
 Mark all blocks in free list as defined.
static void valgrind_make_blocks_noaccess (void)
 Mark all blocks in free list as inaccessible.
static void check_blocks (void)
 Check integrity of the blocks in the free list.
static unsigned int discard_cache (void)
 Discard some cached data.
static void discard_all_cache (void)
 Discard all cached data.
void * alloc_memblock (size_t size, size_t align, size_t offset)
 Allocate a memory block.
void free_memblock (void *ptr, size_t size)
 Free a memory block.
void * realloc (void *old_ptr, size_t new_size)
 Reallocate memory.
void * malloc (size_t size)
 Allocate memory.
void free (void *ptr)
 Free memory.
void * zalloc (size_t size)
 Allocate cleared memory.
void mpopulate (void *start, size_t len)
 Add memory to allocation pool.
static void init_heap (void)
 Initialise the heap.
struct init_fn heap_init_fn __init_fn (INIT_EARLY)
 Memory allocator initialisation function.
static void shutdown_cache (int booting __unused)
 Discard all cached data on shutdown.
struct startup_fn heap_startup_fn __startup_fn (STARTUP_EARLY)
 Memory allocator shutdown function.

Variables

size_t freemem
 Total amount of free memory.
size_t usedmem
 Total amount of used memory.
size_t maxusedmem
 Maximum amount of used memory.
static char heap [HEAP_SIZE]
 The heap itself.

Detailed Description

Dynamic memory allocation.

Definition in file malloc.c.


Define Documentation

#define MIN_MEMBLOCK_SIZE   ( ( size_t ) ( 1 << ( fls ( sizeof ( struct memory_block ) - 1 ) ) ) )

Definition at line 62 of file malloc.c.

Referenced by alloc_memblock(), check_blocks(), free_memblock(), and mpopulate().

#define NOWHERE   ( ( void * ) ~( ( intptr_t ) 0 ) )

Address for zero-length memory blocks.

malloc(0) or realloc(ptr,0) will return the special value NOWHERE. Calling free(NOWHERE) will have no effect.

This is consistent with the ANSI C standards, which state that "either NULL or a pointer suitable to be passed to free()" must be returned in these cases. Using a special non-NULL value means that the caller can take a NULL return value to indicate failure, without first having to check for a requested size of zero.

Code outside of malloc.c do not ever need to refer to the actual value of NOWHERE; this is an internal definition.

Definition at line 88 of file malloc.c.

Referenced by realloc().

#define HEAP_SIZE   ( 512 * 1024 )

Heap size.

Currently fixed at 512kB.

Definition at line 107 of file malloc.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static LIST_HEAD ( free_blocks  ) [static]

List of free memory blocks.

static void valgrind_make_blocks_defined ( void  ) [inline, static]

Mark all blocks in free list as defined.

Definition at line 116 of file malloc.c.

References block, memory_block::list, list_for_each_entry, list_head::next, list_head::prev, RUNNING_ON_VALGRIND, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by alloc_memblock(), and free_memblock().

                                                         {
        struct memory_block *block;

        /* Do nothing unless running under Valgrind */
        if ( RUNNING_ON_VALGRIND <= 0 )
                return;

        /* Traverse free block list, marking each block structure as
         * defined.  Some contortions are necessary to avoid errors
         * from list_check().
         */

        /* Mark block list itself as defined */
        VALGRIND_MAKE_MEM_DEFINED ( &free_blocks, sizeof ( free_blocks ) );

        /* Mark areas accessed by list_check() as defined */
        VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.prev->next,
                                    sizeof ( free_blocks.prev->next ) );
        VALGRIND_MAKE_MEM_DEFINED ( free_blocks.next,
                                    sizeof ( *free_blocks.next ) );
        VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->next->prev,
                                    sizeof ( free_blocks.next->next->prev ) );

        /* Mark each block in list as defined */
        list_for_each_entry ( block, &free_blocks, list ) {

                /* Mark block as defined */
                VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );

                /* Mark areas accessed by list_check() as defined */
                VALGRIND_MAKE_MEM_DEFINED ( block->list.next,
                                            sizeof ( *block->list.next ) );
                VALGRIND_MAKE_MEM_DEFINED ( &block->list.next->next->prev,
                                      sizeof ( block->list.next->next->prev ) );
        }
}
static void valgrind_make_blocks_noaccess ( void  ) [inline, static]

Mark all blocks in free list as inaccessible.

Definition at line 157 of file malloc.c.

References block, memory_block::list, list_for_each_entry, NULL, RUNNING_ON_VALGRIND, VALGRIND_MAKE_MEM_DEFINED, and VALGRIND_MAKE_MEM_NOACCESS.

Referenced by alloc_memblock(), and free_memblock().

                                                          {
        struct memory_block *block;
        struct memory_block *prev = NULL;

        /* Do nothing unless running under Valgrind */
        if ( RUNNING_ON_VALGRIND <= 0 )
                return;

        /* Traverse free block list, marking each block structure as
         * inaccessible.  Some contortions are necessary to avoid
         * errors from list_check().
         */

        /* Mark each block in list as inaccessible */
        list_for_each_entry ( block, &free_blocks, list ) {

                /* Mark previous block (if any) as inaccessible. (Current
                 * block will be accessed by list_check().)
                 */
                if ( prev )
                        VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
                prev = block;

                /* At the end of the list, list_check() will end up
                 * accessing the first list item.  Temporarily mark
                 * this area as defined.
                 */
                VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->prev,
                                            sizeof ( free_blocks.next->prev ) );
        }
        /* Mark last block (if any) as inaccessible */
        if ( prev )
                VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );

        /* Mark as inaccessible the area that was temporarily marked
         * as defined to avoid errors from list_check().
         */
        VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks.next->prev,
                                     sizeof ( free_blocks.next->prev ) );

        /* Mark block list itself as inaccessible */
        VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
}
static void check_blocks ( void  ) [inline, static]

Check integrity of the blocks in the free list.

Definition at line 205 of file malloc.c.

References assert, block, memory_block::list, list_check, list_for_each_entry, MIN_MEMBLOCK_SIZE, NULL, and memory_block::size.

Referenced by alloc_memblock(), and free_memblock().

                                         {
        struct memory_block *block;
        struct memory_block *prev = NULL;

        if ( ! ASSERTING )
                return;

        list_for_each_entry ( block, &free_blocks, list ) {

                /* Check that list structure is intact */
                list_check ( &block->list );

                /* Check that block size is not too small */
                assert ( block->size >= sizeof ( *block ) );
                assert ( block->size >= MIN_MEMBLOCK_SIZE );

                /* Check that block does not wrap beyond end of address space */
                assert ( ( ( void * ) block + block->size ) >
                         ( ( void * ) block ) );

                /* Check that blocks remain in ascending order, and
                 * that adjacent blocks have been merged.
                 */
                if ( prev ) {
                        assert ( ( ( void * ) block ) > ( ( void * ) prev ) );
                        assert ( ( ( void * ) block ) >
                                 ( ( ( void * ) prev ) + prev->size ) );
                }
                prev = block;
        }
}
static unsigned int discard_cache ( void  ) [static]

Discard some cached data.

Return values:
discardedNumber of cached items discarded

Definition at line 242 of file malloc.c.

References CACHE_DISCARDERS, cache_discarder::discard, and for_each_table_entry.

Referenced by alloc_memblock(), and discard_all_cache().

                                           {
        struct cache_discarder *discarder;
        unsigned int discarded;

        for_each_table_entry ( discarder, CACHE_DISCARDERS ) {
                discarded = discarder->discard();
                if ( discarded )
                        return discarded;
        }
        return 0;
}
static void discard_all_cache ( void  ) [static]

Discard all cached data.

Definition at line 258 of file malloc.c.

References discard_cache().

Referenced by shutdown_cache().

                                       {
        unsigned int discarded;

        do {
                discarded = discard_cache();
        } while ( discarded );
}
void* alloc_memblock ( size_t  size,
size_t  align,
size_t  offset 
)

Allocate a memory block.

Parameters:
sizeRequested size
alignPhysical alignment
offsetOffset from physical alignment
Return values:
ptrMemory block, or NULL

Allocates a memory block physically aligned as requested. No guarantees are provided for the alignment of the virtual address.

align must be a power of two. size may not be zero.

Definition at line 279 of file malloc.c.

References assert, block, check_blocks(), DBGC, DBGC2, discard_cache(), done, freemem, heap, memory_block::list, list_add, list_del, list_for_each_entry, maxusedmem, MIN_MEMBLOCK_SIZE, NULL, memory_block::size, usedmem, valgrind_make_blocks_defined(), valgrind_make_blocks_noaccess(), VALGRIND_MAKE_MEM_NOACCESS, VALGRIND_MAKE_MEM_UNDEFINED, and virt_to_phys().

Referenced by malloc_dma_offset(), and realloc().

                                                                   {
        struct memory_block *block;
        size_t align_mask;
        size_t actual_size;
        size_t pre_size;
        size_t post_size;
        struct memory_block *pre;
        struct memory_block *post;
        unsigned int discarded;
        void *ptr;

        /* Sanity checks */
        assert ( size != 0 );
        assert ( ( align == 0 ) || ( ( align & ( align - 1 ) ) == 0 ) );
        valgrind_make_blocks_defined();
        check_blocks();

        /* Round up size to multiple of MIN_MEMBLOCK_SIZE and
         * calculate alignment mask.
         */
        actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
                        ~( MIN_MEMBLOCK_SIZE - 1 ) );
        if ( ! actual_size ) {
                /* The requested size is not permitted to be zero.  A
                 * zero result at this point indicates that either the
                 * original requested size was zero, or that unsigned
                 * integer overflow has occurred.
                 */
                ptr = NULL;
                goto done;
        }
        assert ( actual_size >= size );
        align_mask = ( ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 ) );

        DBGC2 ( &heap, "Allocating %#zx (aligned %#zx+%zx)\n",
                size, align, offset );
        while ( 1 ) {
                /* Search through blocks for the first one with enough space */
                list_for_each_entry ( block, &free_blocks, list ) {
                        pre_size = ( ( offset - virt_to_phys ( block ) )
                                     & align_mask );
                        if ( ( block->size < pre_size ) ||
                             ( ( block->size - pre_size ) < actual_size ) )
                                continue;
                        post_size = ( block->size - pre_size - actual_size );
                        /* Split block into pre-block, block, and
                         * post-block.  After this split, the "pre"
                         * block is the one currently linked into the
                         * free list.
                         */
                        pre   = block;
                        block = ( ( ( void * ) pre   ) + pre_size );
                        post  = ( ( ( void * ) block ) + actual_size );
                        DBGC2 ( &heap, "[%p,%p) -> [%p,%p) + [%p,%p)\n", pre,
                                ( ( ( void * ) pre ) + pre->size ), pre, block,
                                post, ( ( ( void * ) pre ) + pre->size ) );
                        /* If there is a "post" block, add it in to
                         * the free list.  Leak it if it is too small
                         * (which can happen only at the very end of
                         * the heap).
                         */
                        if ( post_size >= MIN_MEMBLOCK_SIZE ) {
                                VALGRIND_MAKE_MEM_UNDEFINED ( post,
                                                              sizeof ( *post ));
                                post->size = post_size;
                                list_add ( &post->list, &pre->list );
                        }
                        /* Shrink "pre" block, leaving the main block
                         * isolated and no longer part of the free
                         * list.
                         */
                        pre->size = pre_size;
                        /* If there is no "pre" block, remove it from
                         * the list.  Also remove it (i.e. leak it) if
                         * it is too small, which can happen only at
                         * the very start of the heap.
                         */
                        if ( pre_size < MIN_MEMBLOCK_SIZE ) {
                                list_del ( &pre->list );
                                VALGRIND_MAKE_MEM_NOACCESS ( pre,
                                                             sizeof ( *pre ) );
                        }
                        /* Update memory usage statistics */
                        freemem -= actual_size;
                        usedmem += actual_size;
                        if ( usedmem > maxusedmem )
                                maxusedmem = usedmem;
                        /* Return allocated block */
                        DBGC2 ( &heap, "Allocated [%p,%p)\n", block,
                                ( ( ( void * ) block ) + size ) );
                        ptr = block;
                        VALGRIND_MAKE_MEM_UNDEFINED ( ptr, size );
                        goto done;
                }

                /* Try discarding some cached data to free up memory */
                DBGC ( &heap, "Attempting discard for %#zx (aligned %#zx+%zx), "
                       "used %zdkB\n", size, align, offset, ( usedmem >> 10 ) );
                valgrind_make_blocks_noaccess();
                discarded = discard_cache();
                valgrind_make_blocks_defined();
                check_blocks();
                if ( ! discarded ) {
                        /* Nothing available to discard */
                        DBGC ( &heap, "Failed to allocate %#zx (aligned "
                               "%#zx)\n", size, align );
                        ptr = NULL;
                        goto done;
                }
        }

 done:
        check_blocks();
        valgrind_make_blocks_noaccess();
        return ptr;
}
void free_memblock ( void *  ptr,
size_t  size 
)

Free a memory block.

Parameters:
ptrMemory allocated by alloc_memblock(), or NULL
sizeSize of the memory

If ptr is NULL, no action is taken.

Definition at line 404 of file malloc.c.

References assert, block, check_blocks(), DBGC, DBGC2, freemem, heap, memory_block::list, list_add_tail, list_del, list_for_each_entry, list_for_each_entry_safe, MIN_MEMBLOCK_SIZE, usedmem, valgrind_make_blocks_defined(), valgrind_make_blocks_noaccess(), VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MAKE_MEM_UNDEFINED.

Referenced by free_dma(), mpopulate(), and realloc().

                                              {
        struct memory_block *freeing;
        struct memory_block *block;
        struct memory_block *tmp;
        size_t actual_size;
        ssize_t gap_before;
        ssize_t gap_after = -1;

        /* Allow for ptr==NULL */
        if ( ! ptr )
                return;
        VALGRIND_MAKE_MEM_NOACCESS ( ptr, size );

        /* Sanity checks */
        valgrind_make_blocks_defined();
        check_blocks();

        /* Round up size to match actual size that alloc_memblock()
         * would have used.
         */
        assert ( size != 0 );
        actual_size = ( ( size + MIN_MEMBLOCK_SIZE - 1 ) &
                        ~( MIN_MEMBLOCK_SIZE - 1 ) );
        freeing = ptr;
        VALGRIND_MAKE_MEM_UNDEFINED ( freeing, sizeof ( *freeing ) );
        DBGC2 ( &heap, "Freeing [%p,%p)\n",
                freeing, ( ( ( void * ) freeing ) + size ) );

        /* Check that this block does not overlap the free list */
        if ( ASSERTING ) {
                list_for_each_entry ( block, &free_blocks, list ) {
                        if ( ( ( ( void * ) block ) <
                               ( ( void * ) freeing + actual_size ) ) &&
                             ( ( void * ) freeing <
                               ( ( void * ) block + block->size ) ) ) {
                                assert ( 0 );
                                DBGC ( &heap, "Double free of [%p,%p) "
                                       "overlapping [%p,%p) detected from %p\n",
                                       freeing,
                                       ( ( ( void * ) freeing ) + size ), block,
                                       ( ( void * ) block + block->size ),
                                       __builtin_return_address ( 0 ) );
                        }
                }
        }

        /* Insert/merge into free list */
        freeing->size = actual_size;
        list_for_each_entry_safe ( block, tmp, &free_blocks, list ) {
                /* Calculate gaps before and after the "freeing" block */
                gap_before = ( ( ( void * ) freeing ) - 
                               ( ( ( void * ) block ) + block->size ) );
                gap_after = ( ( ( void * ) block ) - 
                              ( ( ( void * ) freeing ) + freeing->size ) );
                /* Merge with immediately preceding block, if possible */
                if ( gap_before == 0 ) {
                        DBGC2 ( &heap, "[%p,%p) + [%p,%p) -> [%p,%p)\n", block,
                                ( ( ( void * ) block ) + block->size ), freeing,
                                ( ( ( void * ) freeing ) + freeing->size ),
                                block,
                                ( ( ( void * ) freeing ) + freeing->size ) );
                        block->size += actual_size;
                        list_del ( &block->list );
                        VALGRIND_MAKE_MEM_NOACCESS ( freeing,
                                                     sizeof ( *freeing ) );
                        freeing = block;
                }
                /* Stop processing as soon as we reach a following block */
                if ( gap_after >= 0 )
                        break;
        }

        /* Insert before the immediately following block.  If
         * possible, merge the following block into the "freeing"
         * block.
         */
        DBGC2 ( &heap, "[%p,%p)\n",
                freeing, ( ( ( void * ) freeing ) + freeing->size ) );
        list_add_tail ( &freeing->list, &block->list );
        if ( gap_after == 0 ) {
                DBGC2 ( &heap, "[%p,%p) + [%p,%p) -> [%p,%p)\n", freeing,
                        ( ( ( void * ) freeing ) + freeing->size ), block,
                        ( ( ( void * ) block ) + block->size ), freeing,
                        ( ( ( void * ) block ) + block->size ) );
                freeing->size += block->size;
                list_del ( &block->list );
                VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
        }

        /* Update memory usage statistics */
        freemem += actual_size;
        usedmem -= actual_size;

        check_blocks();
        valgrind_make_blocks_noaccess();
}
void* realloc ( void *  old_ptr,
size_t  new_size 
)

Reallocate memory.

Parameters:
old_ptrMemory previously allocated by malloc(), or NULL
new_sizeRequested size
Return values:
new_ptrAllocated memory, or NULL

Allocates memory with no particular alignment requirement. new_ptr will be aligned to at least a multiple of sizeof(void*). If old_ptr is non-NULL, then the contents of the newly allocated memory will be the same as the contents of the previously allocated memory, up to the minimum of the old and new sizes. The old memory will be freed.

If allocation fails the previously allocated block is left untouched and NULL is returned.

Calling realloc() with a new size of zero is a valid way to free a memory block.

Definition at line 521 of file malloc.c.

References alloc_memblock(), assert, ASSERTED, container_of, autosized_block::data, data, DBGC, free_memblock(), heap, memcpy(), NOWHERE, NULL, offsetof, autosized_block::size, VALGRIND_FREELIKE_BLOCK, VALGRIND_MAKE_MEM_DEFINED, VALGRIND_MAKE_MEM_NOACCESS, and VALGRIND_MALLOCLIKE_BLOCK.

Referenced by asn1_grow(), bitmap_resize(), cachedhcp_init(), dhcpopt_init(), efi_ifr_op(), efi_ifr_string(), free(), ibft_alloc_string(), ibft_install(), line_buffer(), malloc(), nvo_realloc(), process_script(), and xferbuf_malloc_realloc().

                                                  {
        struct autosized_block *old_block;
        struct autosized_block *new_block;
        size_t old_total_size;
        size_t new_total_size;
        size_t old_size;
        void *new_ptr = NOWHERE;

        /* Allocate new memory if necessary.  If allocation fails,
         * return without touching the old block.
         */
        if ( new_size ) {
                new_total_size = ( new_size +
                                   offsetof ( struct autosized_block, data ) );
                if ( new_total_size < new_size )
                        return NULL;
                new_block = alloc_memblock ( new_total_size, 1, 0 );
                if ( ! new_block )
                        return NULL;
                new_block->size = new_total_size;
                VALGRIND_MAKE_MEM_NOACCESS ( &new_block->size,
                                             sizeof ( new_block->size ) );
                new_ptr = &new_block->data;
                VALGRIND_MALLOCLIKE_BLOCK ( new_ptr, new_size, 0, 0 );
        }
        
        /* Copy across relevant part of the old data region (if any),
         * then free it.  Note that at this point either (a) new_ptr
         * is valid, or (b) new_size is 0; either way, the memcpy() is
         * valid.
         */
        if ( old_ptr && ( old_ptr != NOWHERE ) ) {
                old_block = container_of ( old_ptr, struct autosized_block,
                                           data );
                VALGRIND_MAKE_MEM_DEFINED ( &old_block->size,
                                            sizeof ( old_block->size ) );
                old_total_size = old_block->size;
                assert ( old_total_size != 0 );
                old_size = ( old_total_size -
                             offsetof ( struct autosized_block, data ) );
                memcpy ( new_ptr, old_ptr,
                         ( ( old_size < new_size ) ? old_size : new_size ) );
                VALGRIND_FREELIKE_BLOCK ( old_ptr, 0 );
                free_memblock ( old_block, old_total_size );
        }

        if ( ASSERTED ) {
                DBGC ( &heap, "Possible memory corruption detected from %p\n",
                       __builtin_return_address ( 0 ) );
        }
        return new_ptr;
}
void* malloc ( size_t  size)

Allocate memory.

Parameters:
sizeRequested size
Return values:
ptrMemory, or NULL

Allocates memory with no particular alignment requirement. ptr will be aligned to at least a multiple of sizeof(void*).

Definition at line 583 of file malloc.c.

References ASSERTED, DBGC, heap, NULL, and realloc().

Referenced by add_ipv4_miniroute(), add_tls(), aes_unwrap(), aes_wrap(), alloc_iob_raw(), apply_dns_search(), ath5k_hw_rfregs_init(), chap_init(), cmdline_init(), cms_parse_signature_value(), deflate_test_exec(), der_asn1(), derwin(), dhcpv6_rx(), dupwin(), efi_download_start(), efi_local_check_volume_name(), efi_local_len(), eisabus_probe(), fc_ulp_login(), fetch_setting_copy(), format_uri_alloc(), http_format_ntlm_auth(), int13_hook(), ipoib_map_remac(), isabus_probe(), isapnpbus_probe(), iscsi_rx_buffered_data(), iscsi_scsi_command(), jme_alloc_rx_resources(), jme_alloc_tx_resources(), loopback_test(), mcabus_probe(), memcpy_test_speed(), mlx_memory_alloc_priv(), net80211_probe_start(), net80211_register(), newwin(), nfs_uri_symlink(), ntlm_authenticate_okx(), ocsp_response(), ocsp_uri_string(), parse_kv(), parse_net_args(), pci_vpd_resize(), pcibus_probe(), peerblk_decrypt(), peerblk_parse_header(), pem_asn1(), rsa_alloc(), sandev_parse_iso9660(), storef_setting(), storen_setting(), strndup(), t509bus_probe(), tls_assemble_block(), tls_assemble_stream(), uhci_enqueue(), usb_config_descriptor(), usb_get_string_descriptor(), usbio_config(), usbio_path(), vasprintf(), vesafb_mode_list(), vmbus_open(), wpa_make_rsn_ie(), wpa_start(), and zalloc().

                              {
        void *ptr;

        ptr = realloc ( NULL, size );
        if ( ASSERTED ) {
                DBGC ( &heap, "Possible memory corruption detected from %p\n",
                       __builtin_return_address ( 0 ) );
        }
        return ptr;
}
void free ( void *  ptr)

Free memory.

Parameters:
ptrMemory allocated by malloc(), or NULL

Memory allocated with malloc_dma() cannot be freed with free(); it must be freed with free_dma() instead.

If ptr is NULL, no action is taken.

Definition at line 604 of file malloc.c.

References ASSERTED, DBGC, heap, and realloc().

                        {

        realloc ( ptr, 0 );
        if ( ASSERTED ) {
                DBGC ( &heap, "Possible memory corruption detected from %p\n",
                       __builtin_return_address ( 0 ) );
        }
}
void* zalloc ( size_t  size)

Allocate cleared memory.

Parameters:
sizeRequested size
Return values:
ptrAllocated memory

Allocate memory as per malloc(), and zero it.

This function name is non-standard, but pretty intuitive. zalloc(size) is always equivalent to calloc(1,size)

Definition at line 624 of file malloc.c.

References ASSERTED, data, DBGC, heap, malloc(), and memset().

Referenced by add_menu_item(), add_parameter(), alloc_ibdev(), alloc_image(), alloc_netdev(), alloc_pixbuf(), alloc_sandev(), alloc_usb(), alloc_usb_bus(), alloc_usb_hub(), aoecmd_create(), aoedev_open(), ar9300_eeprom_restore_internal(), arbel_alloc(), arbel_create_cq(), arbel_create_qp(), ata_open(), atadev_command(), ath5k_hw_attach(), ath5k_probe(), ath9k_init_softc(), ath_descdma_setup(), atl1e_setup_ring_resources(), autovivify_child_settings(), block_translate(), cachedhcp_init(), calloc(), cms_parse(), cms_signature(), concat_args(), create_downloader(), create_menu(), create_parameters(), create_pinger(), create_validator(), dhcp_deliver(), dhcpv6_register(), dns_resolv(), efi_block_boot_image(), efi_block_install(), efi_driver_start(), efi_file_open(), efi_image_cmdline(), efi_image_path(), efi_local_open(), efi_pxe_install(), efi_snp_hii_fetch(), efi_snp_hii_install(), efi_snp_hii_process(), efi_snp_hii_store(), efi_snp_probe(), efi_usb_install(), efi_usb_open(), efi_usb_probe(), efipci_start(), ehci_endpoint_open(), ehci_probe(), ehci_ring_alloc(), eoib_create_peer(), exanic_probe(), fc_els_create(), fc_ns_query(), fc_peer_create(), fc_port_open(), fc_ulp_create(), fc_xchg_create(), fcoe_probe(), fcpdev_open(), fcpdev_scsi_command(), fetch_string_setting_copy_alloc(), fetchf_setting_copy(), flexboot_nodnic_create_cq(), flexboot_nodnic_create_qp(), flexboot_nodnic_eth_open(), flexboot_nodnic_probe(), fragment_reassemble(), ftp_open(), generic_settings_store(), golan_alloc(), golan_create_cq(), golan_create_qp_aux(), guestinfo_fetch_type(), guestinfo_net_probe(), hermon_alloc(), hermon_create_cq(), hermon_create_qp(), http_connect(), http_open(), http_open_post_uri(), hub_probe(), hv_probe(), hvm_probe(), hw_open(), ib_cmrc_open(), ib_create_conn(), ib_create_cq(), ib_create_madx(), ib_create_mi(), ib_create_path(), ib_create_qp(), ib_mcast_attach(), ib_srp_open(), ibft_install(), init_mlx_utils(), ipv6_add_miniroute(), ipv6_register_settings(), iscsi_open(), linda_create_send_wq(), mlx_memory_zalloc_priv(), ndp_register_settings(), neighbour_create(), net80211_handle_mgmt(), net80211_prepare_assoc(), net80211_probe_start(), net80211_probe_step(), net80211_step_associate(), nfs_open(), nii_map(), numeric_resolv(), ocsp_check(), ocsp_uri_string(), open(), parse_uri(), peerblk_open(), peerdisc_create(), peerdisc_discovered(), peermux_filter(), ping_open(), png_pixbuf(), pxe_menu_parse(), qib7322_create_send_bufs(), qib7322_create_send_wq(), qib7322_probe(), rc80211_init(), resolv(), resolv_setting(), rtl818x_probe(), scsi_open(), scsidev_command(), sec80211_install(), sis190_mii_probe(), skge_probe(), skge_ring_alloc(), sky2_probe(), sky2_up(), slam_open(), srp_open(), srpdev_scsi_command(), start_dhcp(), start_dhcpv6(), start_ipv6conf(), start_ntp(), start_pxebs(), tcp_open(), tftp_core_open(), tg3_alloc_consistent(), tls_send_certificate(), tls_set_cipher(), txnic_bgx_probe(), txnic_pf_probe(), udp_open_common(), uhci_endpoint_open(), uhci_probe(), undipci_probe(), undirom_probe(), uri_dup(), usb_probe_all(), usbio_endpoint_open(), usbio_interfaces(), usbio_interrupt_open(), usbio_start(), usbkbd_probe(), validator_start_download(), virtnet_open_legacy(), virtnet_open_modern(), vmbus_probe(), vmbus_probe_channels(), vp_alloc_vq(), vxge_hw_device_initialize(), x509_alloc_chain(), x509_append(), x509_certificate(), xcm_create(), xenbus_probe_device(), xenstore_response(), xfer_open_named_socket(), xhci_bus_open(), xhci_device_open(), xhci_endpoint_open(), xhci_probe(), xhci_ring_alloc(), xsigo_ib_probe(), and xve_create().

                              {
        void *data;

        data = malloc ( size );
        if ( data )
                memset ( data, 0, size );
        if ( ASSERTED ) {
                DBGC ( &heap, "Possible memory corruption detected from %p\n",
                       __builtin_return_address ( 0 ) );
        }
        return data;
}
void mpopulate ( void *  start,
size_t  len 
)

Add memory to allocation pool.

Parameters:
startStart address
endEnd address

Adds a block of memory [start,end) to the allocation pool. This is a one-way operation; there is no way to reclaim this memory.

start must be aligned to at least a multiple of sizeof(void*).

Definition at line 648 of file malloc.c.

References free_memblock(), len, MIN_MEMBLOCK_SIZE, and usedmem.

Referenced by init_heap().

                                           {

        /* Prevent free_memblock() from rounding up len beyond the end
         * of what we were actually given...
         */
        len &= ~( MIN_MEMBLOCK_SIZE - 1 );

        /* Add to allocation pool */
        free_memblock ( start, len );

        /* Fix up memory usage statistics */
        usedmem += len;
}
static void init_heap ( void  ) [static]

Initialise the heap.

Definition at line 666 of file malloc.c.

References heap, mpopulate(), and VALGRIND_MAKE_MEM_NOACCESS.

                               {
        VALGRIND_MAKE_MEM_NOACCESS ( heap, sizeof ( heap ) );
        VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
        mpopulate ( heap, sizeof ( heap ) );
}
struct init_fn heap_init_fn __init_fn ( INIT_EARLY  ) [read]

Memory allocator initialisation function.

static void shutdown_cache ( int booting  __unused) [static]

Discard all cached data on shutdown.

Definition at line 681 of file malloc.c.

References DBGC, discard_all_cache(), heap, and maxusedmem.

                                                    {
        discard_all_cache();
        DBGC ( &heap, "Maximum heap usage %zdkB\n", ( maxusedmem >> 10 ) );
}
struct startup_fn heap_startup_fn __startup_fn ( STARTUP_EARLY  ) [read]

Memory allocator shutdown function.


Variable Documentation

Total amount of free memory.

Definition at line 94 of file malloc.c.

Referenced by alloc_memblock(), and free_memblock().

Total amount of used memory.

Definition at line 97 of file malloc.c.

Referenced by alloc_memblock(), free_memblock(), and mpopulate().

Maximum amount of used memory.

Definition at line 100 of file malloc.c.

Referenced by alloc_memblock(), and shutdown_cache().

char heap[HEAP_SIZE] [static]

The heap itself.

Definition at line 110 of file malloc.c.

Referenced by alloc_memblock(), free(), free_memblock(), init_heap(), malloc(), realloc(), shutdown_cache(), and zalloc().