[umalloc] Remove userptr_t from user memory allocations

Use standard void pointers for umalloc(), urealloc(), and ufree(),
with the "u" prefix retained to indicate that these allocations are
made from external ("user") memory rather than from the internal heap.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-04-23 12:47:53 +01:00
parent 0bf0f8716a
commit 839540cb95
13 changed files with 101 additions and 151 deletions

View File

@@ -32,23 +32,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Equivalent of NOWHERE for user pointers */
#define UNOWHERE ( ~UNULL )
/**
* Reallocate external memory
*
* @v old_ptr Memory previously allocated by umalloc(), or UNULL
* @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
* @ret new_ptr Allocated memory, or UNULL
* @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
static userptr_t sbi_urealloc ( userptr_t old_ptr, size_t new_size ) {
static void * sbi_urealloc ( void * old_ptr, size_t new_size ) {
/* External allocation not yet implemented: allocate from heap */
return ( ( userptr_t ) realloc ( ( ( void * ) old_ptr ), new_size ) );
return ( realloc ( old_ptr, new_size ) );
}
PROVIDE_UMALLOC ( sbi, urealloc, sbi_urealloc );

View File

@@ -44,9 +44,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Alignment of external allocated memory */
#define EM_ALIGN ( 4 * 1024 )
/** Equivalent of NOWHERE for user pointers */
#define UNOWHERE ( ( userptr_t ) ~( ( intptr_t ) 0 ) )
/** An external memory block */
struct external_memory {
/** Size of this memory block (excluding this header) */
@@ -56,10 +53,10 @@ struct external_memory {
};
/** Top of heap */
static userptr_t top = UNULL;
static void *top = NULL;
/** Bottom of heap (current lowest allocated block) */
static userptr_t bottom = UNULL;
static void *bottom = NULL;
/** Remaining space on heap */
static size_t heap_size;
@@ -70,7 +67,7 @@ static size_t heap_size;
* @ret start Start of region
* @ret len Length of region
*/
size_t largest_memblock ( userptr_t *start ) {
size_t largest_memblock ( void **start ) {
struct memory_map memmap;
struct memory_region *region;
physaddr_t max = EM_MAX_ADDRESS;
@@ -81,7 +78,7 @@ size_t largest_memblock ( userptr_t *start ) {
size_t len = 0;
/* Avoid returning uninitialised data on error */
*start = UNULL;
*start = NULL;
/* Scan through all memory regions */
get_memmap ( &memmap );
@@ -119,7 +116,7 @@ size_t largest_memblock ( userptr_t *start ) {
*
*/
static void init_eheap ( void ) {
userptr_t base;
void *base;
heap_size = largest_memblock ( &base );
bottom = top = ( base + heap_size );
@@ -137,8 +134,8 @@ static void ecollect_free ( void ) {
/* Walk the free list and collect empty blocks */
while ( bottom != top ) {
copy_from_user ( &extmem, bottom, -sizeof ( extmem ),
sizeof ( extmem ) );
memcpy ( &extmem, ( bottom - sizeof ( extmem ) ),
sizeof ( extmem ) );
if ( extmem.used )
break;
DBG ( "EXTMEM freeing [%lx,%lx)\n", virt_to_phys ( bottom ),
@@ -152,16 +149,16 @@ static void ecollect_free ( void ) {
/**
* Reallocate external memory
*
* @v old_ptr Memory previously allocated by umalloc(), or UNULL
* @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
* @ret new_ptr Allocated memory, or UNULL
* @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
static void * memtop_urealloc ( void *ptr, size_t new_size ) {
struct external_memory extmem;
userptr_t new = ptr;
void *new = ptr;
size_t align;
/* (Re)initialise external memory allocator if necessary */
@@ -169,15 +166,15 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
init_eheap();
/* Get block properties into extmem */
if ( ptr && ( ptr != UNOWHERE ) ) {
if ( ptr && ( ptr != NOWHERE ) ) {
/* Determine old size */
copy_from_user ( &extmem, ptr, -sizeof ( extmem ),
sizeof ( extmem ) );
memcpy ( &extmem, ( ptr - sizeof ( extmem ) ),
sizeof ( extmem ) );
} else {
/* Create a zero-length block */
if ( heap_size < sizeof ( extmem ) ) {
DBG ( "EXTMEM out of space\n" );
return UNULL;
return NULL;
}
ptr = bottom = ( bottom - sizeof ( extmem ) );
heap_size -= sizeof ( extmem );
@@ -196,7 +193,7 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
new -= align;
if ( new_size > ( heap_size + extmem.size ) ) {
DBG ( "EXTMEM out of space\n" );
return UNULL;
return NULL;
}
DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n",
virt_to_phys ( ptr ),
@@ -215,13 +212,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
DBG ( "EXTMEM cannot expand [%lx,%lx)\n",
virt_to_phys ( ptr ),
( virt_to_phys ( ptr ) + extmem.size ) );
return UNULL;
return NULL;
}
}
/* Write back block properties */
copy_to_user ( new, -sizeof ( extmem ), &extmem,
sizeof ( extmem ) );
memcpy ( ( new - sizeof ( extmem ) ), &extmem, sizeof ( extmem ) );
/* Collect any free blocks and update hidden memory region */
ecollect_free();
@@ -229,7 +225,7 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
( ( bottom == top ) ? 0 : sizeof ( extmem ) ) ),
virt_to_phys ( top ) );
return ( new_size ? new : UNOWHERE );
return ( new_size ? new : NOWHERE );
}
PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc );

View File

@@ -130,9 +130,9 @@ static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) {
* @v align Physical alignment
* @ret addr Buffer address, or NULL on error
*/
static userptr_t dma_op_umalloc ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align ) {
static void * dma_op_umalloc ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align ) {
struct dma_operations *op = dma->op;
if ( ! op )
@@ -147,8 +147,7 @@ static userptr_t dma_op_umalloc ( struct dma_device *dma,
* @v addr Buffer address
* @v len Length of buffer
*/
static void dma_op_ufree ( struct dma_mapping *map, userptr_t addr,
size_t len ) {
static void dma_op_ufree ( struct dma_mapping *map, void *addr, size_t len ) {
struct dma_device *dma = map->dma;
assert ( dma != NULL );

View File

@@ -71,23 +71,6 @@ struct autosized_block {
char data[0];
};
/**
* Address for zero-length memory blocks
*
* @c malloc(0) or @c realloc(ptr,0) will return the special value @c
* NOWHERE. Calling @c 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 @c NOWHERE; this is an internal definition.
*/
#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) )
/** List of free memory blocks */
static LIST_HEAD ( free_blocks );

View File

@@ -237,8 +237,8 @@ struct xfer_buffer_operations xferbuf_malloc_operations = {
* @ret rc Return status code
*/
static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
userptr_t *udata = xferbuf->data;
userptr_t new_udata;
void **udata = xferbuf->data;
void *new_udata;
new_udata = urealloc ( *udata, len );
if ( ! new_udata )
@@ -257,9 +257,9 @@ static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) {
*/
static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset,
const void *data, size_t len ) {
userptr_t *udata = xferbuf->data;
void **udata = xferbuf->data;
copy_to_user ( *udata, offset, data, len );
memcpy ( ( *udata + offset ), data, len );
}
/**
@@ -272,9 +272,9 @@ static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset,
*/
static void xferbuf_umalloc_read ( struct xfer_buffer *xferbuf, size_t offset,
void *data, size_t len ) {
userptr_t *udata = xferbuf->data;
void **udata = xferbuf->data;
copy_from_user ( data, *udata, offset, len );
memcpy ( data, ( *udata + offset ), len );
}
/** umalloc()-based data buffer operations */

View File

@@ -106,9 +106,9 @@ struct dma_operations {
* @v align Physical alignment
* @ret addr Buffer address, or NULL on error
*/
userptr_t ( * umalloc ) ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align );
void * ( * umalloc ) ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align );
/**
* Unmap and free DMA-coherent buffer from external (user) memory
*
@@ -118,7 +118,7 @@ struct dma_operations {
* @v len Length of buffer
*/
void ( * ufree ) ( struct dma_device *dma, struct dma_mapping *map,
userptr_t addr, size_t len );
void *addr, size_t len );
/**
* Set addressable space mask
*
@@ -265,11 +265,11 @@ DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map,
* @v align Physical alignment
* @ret addr Buffer address, or NULL on error
*/
static inline __always_inline userptr_t
static inline __always_inline void *
DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align __unused ) {
userptr_t addr;
void *addr;
/* Allocate buffer */
addr = umalloc ( len );
@@ -292,7 +292,7 @@ DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma,
*/
static inline __always_inline void
DMAAPI_INLINE ( flat, dma_ufree ) ( struct dma_mapping *map,
userptr_t addr, size_t len __unused ) {
void *addr, size_t len __unused ) {
/* Free buffer */
ufree ( addr );
@@ -397,8 +397,8 @@ void dma_free ( struct dma_mapping *map, void *addr, size_t len );
* @v align Physical alignment
* @ret addr Buffer address, or NULL on error
*/
userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map,
size_t len, size_t align );
void * dma_umalloc ( struct dma_device *dma, struct dma_mapping *map,
size_t len, size_t align );
/**
* Unmap and free DMA-coherent buffer from external (user) memory
@@ -407,7 +407,7 @@ userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map,
* @v addr Buffer address
* @v len Length of buffer
*/
void dma_ufree ( struct dma_mapping *map, userptr_t addr, size_t len );
void dma_ufree ( struct dma_mapping *map, void *addr, size_t len );
/**
* Set addressable space mask

View File

@@ -21,6 +21,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/tables.h>
#include <valgrind/memcheck.h>
/**
* Address for zero-length memory blocks
*
* @c malloc(0) or @c realloc(ptr,0) will return the special value @c
* NOWHERE. Calling @c 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 the memory allocators themselves does not ever need
* to refer to the actual value of @c NOWHERE; this is an internal
* definition.
*/
#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) )
extern size_t freemem;
extern size_t usedmem;
extern size_t maxusedmem;

View File

@@ -10,9 +10,10 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <ipxe/api.h>
#include <ipxe/malloc.h>
#include <config/umalloc.h>
#include <ipxe/uaccess.h>
/**
* Provide a user memory allocation API implementation
@@ -34,36 +35,36 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* Reallocate external memory
*
* @v userptr Memory previously allocated by umalloc(), or UNULL
* @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
* @ret userptr Allocated memory, or UNULL
* @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
userptr_t urealloc ( userptr_t userptr, size_t new_size );
void * urealloc ( void *ptr, size_t new_size );
/**
* Allocate external memory
*
* @v size Requested size
* @ret userptr Memory, or UNULL
* @ret ptr Memory, or NULL
*
* Memory is guaranteed to be aligned to a page boundary.
*/
static inline __always_inline userptr_t umalloc ( size_t size ) {
return urealloc ( UNULL, size );
static inline __always_inline void * umalloc ( size_t size ) {
return urealloc ( NULL, size );
}
/**
* Free external memory
*
* @v userptr Memory allocated by umalloc(), or UNULL
* @v ptr Memory allocated by umalloc(), or NULL
*
* If @c ptr is UNULL, no action is taken.
* If @c ptr is NULL, no action is taken.
*/
static inline __always_inline void ufree ( userptr_t userptr ) {
urealloc ( userptr, 0 );
static inline __always_inline void ufree ( void *ptr ) {
urealloc ( ptr, 0 );
}
#endif /* _IPXE_UMALLOC_H */

View File

@@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/iobuf.h>
#include <ipxe/uaccess.h>
#include <ipxe/interface.h>
#include <ipxe/xfer.h>
@@ -84,7 +83,7 @@ xferbuf_malloc_init ( struct xfer_buffer *xferbuf ) {
* @v data User pointer
*/
static inline __attribute__ (( always_inline )) void
xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, userptr_t *data ) {
xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, void **data ) {
xferbuf->data = data;
xferbuf->op = &xferbuf_umalloc_operations;
}

View File

@@ -640,38 +640,6 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map,
dma->allocated--;
}
/**
* Allocate and map DMA-coherent buffer from external (user) memory
*
* @v dma DMA device
* @v map DMA mapping to fill in
* @v len Length of buffer
* @v align Physical alignment
* @ret addr Buffer address, or NULL on error
*/
static userptr_t efipci_dma_umalloc ( struct dma_device *dma,
struct dma_mapping *map,
size_t len, size_t align ) {
void *addr;
addr = efipci_dma_alloc ( dma, map, len, align );
return virt_to_user ( addr );
}
/**
* Unmap and free DMA-coherent buffer from external (user) memory
*
* @v dma DMA device
* @v map DMA mapping
* @v addr Buffer address
* @v len Length of buffer
*/
static void efipci_dma_ufree ( struct dma_device *dma, struct dma_mapping *map,
userptr_t addr, size_t len ) {
efipci_dma_free ( dma, map, addr, len );
}
/**
* Set addressable space mask
*
@@ -710,8 +678,8 @@ static struct dma_operations efipci_dma_operations = {
.unmap = efipci_dma_unmap,
.alloc = efipci_dma_alloc,
.free = efipci_dma_free,
.umalloc = efipci_dma_umalloc,
.ufree = efipci_dma_ufree,
.umalloc = efipci_dma_alloc,
.ufree = efipci_dma_free,
.set_mask = efipci_dma_set_mask,
};

View File

@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/efi/efi.h>
@@ -35,25 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Equivalent of NOWHERE for user pointers */
#define UNOWHERE ( ( userptr_t ) ~( ( intptr_t ) 0 ) )
/**
* Reallocate external memory
*
* @v old_ptr Memory previously allocated by umalloc(), or UNULL
* @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
* @ret new_ptr Allocated memory, or UNULL
* @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
static void * efi_urealloc ( void *old_ptr, size_t new_size ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_PHYSICAL_ADDRESS phys_addr;
unsigned int new_pages, old_pages;
userptr_t new_ptr = UNOWHERE;
void *new_ptr = NOWHERE;
size_t old_size;
size_t *info;
EFI_STATUS efirc;
int rc;
@@ -69,12 +68,12 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
rc = -EEFI ( efirc );
DBG ( "EFI could not allocate %d pages: %s\n",
new_pages, strerror ( rc ) );
return UNULL;
return NULL;
}
assert ( phys_addr != 0 );
new_ptr = phys_to_virt ( phys_addr + EFI_PAGE_SIZE );
copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
&new_size, sizeof ( new_size ) );
info = ( new_ptr - EFI_PAGE_SIZE );
*info = new_size;
DBG ( "EFI allocated %d pages at %llx\n",
new_pages, phys_addr );
}
@@ -84,9 +83,9 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
* is valid, or (b) new_size is 0; either way, the memcpy() is
* valid.
*/
if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
sizeof ( old_size ) );
if ( old_ptr && ( old_ptr != NOWHERE ) ) {
info = ( old_ptr - EFI_PAGE_SIZE );
old_size = *info;
memcpy ( new_ptr, old_ptr,
( (old_size < new_size) ? old_size : new_size ) );
old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );

View File

@@ -31,9 +31,6 @@ FILE_LICENCE(GPL2_OR_LATER);
#include <ipxe/linux_api.h>
/** Special address returned for empty allocations */
#define NOWHERE ((void *)-1)
/** Poison to make the metadata more unique */
#define POISON 0xa5a5a5a5
#define min(a,b) (((a)<(b))?(a):(b))
@@ -47,7 +44,16 @@ struct metadata
#define SIZE_MD (sizeof(struct metadata))
/** Simple realloc which passes most of the work to mmap(), mremap() and munmap() */
/**
* Reallocate external memory
*
* @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
* @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
static void * linux_realloc(void *ptr, size_t size)
{
struct metadata md = {0, 0};
@@ -136,19 +142,4 @@ static void * linux_realloc(void *ptr, size_t size)
return ptr;
}
/**
* Reallocate external memory
*
* @v old_ptr Memory previously allocated by umalloc(), or UNULL
* @v new_size Requested size
* @ret new_ptr Allocated memory, or UNULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
static userptr_t linux_urealloc(userptr_t old_ptr, size_t new_size)
{
return (userptr_t)linux_realloc((void *)old_ptr, new_size);
}
PROVIDE_UMALLOC(linux, urealloc, linux_urealloc);
PROVIDE_UMALLOC(linux, urealloc, linux_realloc);

View File

@@ -1,12 +1,11 @@
#include <stdio.h>
#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/io.h>
void umalloc_test ( void ) {
struct memory_map memmap;
userptr_t bob;
userptr_t fred;
void *bob;
void *fred;
printf ( "Before allocation:\n" );
get_memmap ( &memmap );