sandbox: Add os_realloc()

We provide os_malloc() and os_free() but not os_realloc(). Add this,
following the usual semantics. Also update os_malloc() to behave correctly
when passed a zero size.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 3d8af0a..d23aad3 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -267,11 +267,18 @@
 	signal(SIGINT, os_sigint_handler);
 }
 
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
 void *os_malloc(size_t length)
 {
 	int page_size = getpagesize();
 	struct os_mem_hdr *hdr;
 
+	if (!length)
+		return NULL;
 	/*
 	 * Use an address that is hopefully available to us so that pointers
 	 * to this memory are fairly obvious. If we end up with a different
@@ -296,6 +303,47 @@
 		hdr = ptr - page_size;
 		munmap(hdr, hdr->length + page_size);
 	}
+}
+
+/* These macros are from kernel.h but not accessible in this file */
+#define ALIGN(x, a)		__ALIGN_MASK((x), (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
+
+/*
+ * Provide our own malloc so we don't use space in the sandbox ram_buf for
+ * allocations that are internal to sandbox, or need to be done before U-Boot's
+ * malloc() is ready.
+ */
+void *os_realloc(void *ptr, size_t length)
+{
+	int page_size = getpagesize();
+	struct os_mem_hdr *hdr;
+	void *new_ptr;
+
+	/* Reallocating a NULL pointer is just an alloc */
+	if (!ptr)
+		return os_malloc(length);
+
+	/* Changing a length to 0 is just a free */
+	if (length) {
+		os_free(ptr);
+		return NULL;
+	}
+
+	/*
+	 * If the new size is the same number of pages as the old, nothing to
+	 * do. There isn't much point in shrinking things
+	 */
+	hdr = ptr - page_size;
+	if (ALIGN(length, page_size) <= ALIGN(hdr->length, page_size))
+		return ptr;
+
+	/* We have to grow it, so allocate something new */
+	new_ptr = os_malloc(length);
+	memcpy(new_ptr, ptr, hdr->length);
+	os_free(ptr);
+
+	return new_ptr;
 }
 
 void os_usleep(unsigned long usec)