Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libc / src / malloc.c
diff --git a/qemu/roms/openhackware/src/libc/src/malloc.c b/qemu/roms/openhackware/src/libc/src/malloc.c
new file mode 100644 (file)
index 0000000..14bd8e5
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * <malloc.c>
+ *
+ * Open Hack'Ware BIOS: memory management
+ * 
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ * 
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License V2
+ *   as published by the Free Software Foundation
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* functions prototypes are here */
+/* NULL is declared here */
+#include <stdlib.h>
+/* memcpy is defined here */
+#include <string.h>
+/* set_errno is defined here */
+#include <errno.h>
+
+//#define DEBUG_MEMOPS
+#if defined (DEBUG_MEMOPS)
+#define MEMOPS_PRINTF(fmt, args...) do { dprintf(fmt , ##args); } while (0)
+#else
+#define MEMOPS_PRINTF(fmt, args...) do { } while (0)
+#endif
+
+#define unused __attribute__ (( unused ))
+
+/* XXX: TODO: put this elsewhere */
+void *page_get (int nb_pages);
+void page_put (void *addr, int nb_pages);
+
+/* XXX: TOTO: put this elsewhere */
+#if defined (__i386__)
+#define NATURAL_ALIGN_BITS 2
+#define PAGE_BITS 12
+#define __32_BITS 1
+#elif defined (__powerpc__) || defined (_ARCH_PPC)
+#define NATURAL_ALIGN_BITS 2
+#define PAGE_BITS 12
+#define __32_BITS 1
+#elif defined (__x86_64__)
+#define NATURAL_ALIGN_BITS 3
+#define PAGE_BITS 12
+#else
+#error "Unsupported architecture"
+#endif
+#define PAGE_SIZE (1 << PAGE_BITS)
+#define PAGE(addr) ((void *)((unsigned long)(addr) & ~(PAGE_SIZE - 1)))
+
+
+#define MIN_ELEM_BITS (NATURAL_ALIGN_BITS + 1)
+#define MIN_ELEM_SIZE (1 << (MIN_ELEM_BITS))
+#define MAX_ELEM_BITS (PAGE_BITS)
+#define MAX_ELEM_SIZE (1 << (MAX_ELEM_BITS - 1))
+#define POOL_MAX ((MAX_ELEM_BITS) - (MIN_ELEM_BITS))
+#define CACHE_MAX 16
+
+typedef struct free_slot_t free_slot_t;
+struct free_slot_t {
+    struct free_slot_t *next;
+};
+
+typedef struct page_descr_t page_descr_t;
+struct page_descr_t {
+    struct page_descr_t *next;
+    struct page_descr_t *prev;
+    void *addr;
+    unsigned long nb;
+};
+
+/*
+ * This points to the first descriptor page where stand:
+ * - 1 descriptor for this page.
+ * - 1 decriptor pages list head.
+ * - POOL_MAX pool descriptors list heads.
+ * - CACHE_MAX page cache entries list heads.
+ */
+static void *malloc_base;
+
+/* Shared functions */
+static inline page_descr_t *main_descr_get (void)
+{
+    return (page_descr_t *)malloc_base + 1;
+}
+
+static inline page_descr_t *pool_head_get (int pool_idx)
+{
+    return main_descr_get() + 1 + pool_idx;
+}
+
+static inline page_descr_t *cache_head_get (int cache_idx)
+{
+    return pool_head_get(POOL_MAX) + 1 + cache_idx;
+}
+
+static void free_slots_init (void *page, int incr, int size)
+{
+    free_slot_t *slot, *next;
+    
+    for (slot = page;
+         slot < (free_slot_t *)((char *)page + size); slot = next) {
+        next = (void *)((char *)slot + incr);
+        slot->next = next;
+    }
+    slot = (void *)((char *)slot - incr);
+    slot->next = NULL;
+}
+
+static page_descr_t *descr_find_free (page_descr_t *head_descr,
+                                      page_descr_t *skip_descr)
+{
+    page_descr_t *cur_descr, *best;
+    unsigned long max_used;
+
+    /* Try to always return the page with the less free slots to reduce
+     * memory fragmentation.
+     */
+    max_used = 0;
+    best = NULL;
+    for (cur_descr = head_descr->next;
+         cur_descr != head_descr; cur_descr = cur_descr->next) {
+        if (cur_descr != skip_descr && cur_descr->addr != NULL &&
+            cur_descr->nb >= max_used) {
+            max_used = cur_descr->nb;
+            best = cur_descr;
+        }
+    }
+
+    return best;
+}
+
+/* Page descriptors management */
+static void page_descr_free (page_descr_t *head_descr)
+{
+    head_descr->next->prev = head_descr->prev;
+    head_descr->prev->next = head_descr->next;
+    page_put(head_descr, 1);
+}
+
+static page_descr_t *page_descr_get (void)
+{
+    page_descr_t *main_descr, *head_descr, *page_descr;
+    free_slot_t *first_free;
+
+    main_descr = main_descr_get();
+    head_descr = main_descr->addr;
+    first_free = head_descr->addr;
+    if (first_free == NULL) {
+        /* Find a page with free descriptors */
+        head_descr = descr_find_free(main_descr, NULL);
+        if (head_descr != NULL) {
+            /* Get the first free slot */
+            first_free = head_descr->addr;
+        } else {
+            /* Allocate a new page */
+            head_descr = page_get(1);
+            if (head_descr == NULL) {
+                MEMOPS_PRINTF("%s: cannot get new head descriptor\n",
+                              __func__);
+                return NULL;
+            }
+            /* Initialise free slots */
+            free_slots_init(head_descr, sizeof(page_descr_t), PAGE_SIZE);
+            /* Initialise page head descriptor */
+            head_descr->addr = head_descr + 1;
+            head_descr->nb = 0;
+            head_descr->next = main_descr;
+            head_descr->prev = main_descr->prev;
+            /* Update main descriptor */
+            main_descr->prev->next = head_descr;
+            main_descr->prev = head_descr;
+            main_descr->nb++;
+            first_free = head_descr->addr;
+        }
+        main_descr->addr = head_descr;
+    }
+    head_descr->addr = first_free->next;
+    if (head_descr->nb == 0)
+        main_descr->nb--;
+    head_descr->nb++;
+    page_descr = (page_descr_t *)first_free;
+    page_descr->prev = NULL;
+    page_descr->next = NULL;
+    page_descr->addr = NULL;
+    page_descr->nb = 0;
+    
+    return page_descr;
+}
+
+static void page_descr_put (page_descr_t *page_descr)
+{
+    page_descr_t *main_descr, *head_descr, *next_descr, *free_descr;
+    free_slot_t *first_free, *next_free;
+    
+    head_descr = PAGE(page_descr);
+    /* Mark this descriptor as free */
+    next_free = head_descr->addr;
+    first_free = (free_slot_t *)page_descr;
+    first_free->next = next_free;
+    /* Update page descriptor */
+    head_descr->addr = first_free;
+    head_descr->nb--;
+    main_descr = main_descr_get();
+    if (head_descr->nb == 0) {
+        /* Try to free this page */
+        if (main_descr->addr == head_descr ||
+            main_descr->addr == NULL ||
+            main_descr->nb > 0)
+            free_descr = descr_find_free(main_descr, head_descr);
+        else
+            free_descr = main_descr->addr;
+        if (free_descr != NULL) {
+            /* Update main descriptor */
+            page_descr_free(head_descr);
+            main_descr->addr = free_descr;
+        } else {
+            main_descr->addr = head_descr;
+            main_descr->nb++;
+        }
+    } else if (next_free == NULL) {
+        free_descr = head_descr;
+        for (head_descr = main_descr->next;
+             main_descr->nb > 0 && head_descr != main_descr;
+             head_descr = next_descr) {
+            next_descr = head_descr->next;
+            if (head_descr->nb == 0) {
+                if (main_descr->addr == head_descr)
+                    main_descr->addr = NULL;
+                page_descr_free(head_descr);
+                main_descr->nb--;
+            }
+        }
+        if (main_descr->addr == NULL)
+            main_descr->addr = free_descr;
+    }
+}
+
+/* Page cache management */
+static inline unsigned long cache_idx (void *addr)
+{
+    return ((unsigned long)addr >> PAGE_BITS) & (CACHE_MAX - 1);
+}
+
+static inline unsigned long page_cache_pool_idx (page_descr_t *cache_descr)
+{
+    return (cache_descr->nb & 0xF);
+}
+
+static inline page_descr_t *page_cache_page_descr (page_descr_t *cache_descr)
+{
+    return (page_descr_t *)(cache_descr->nb & ~0xF);
+}
+
+static int page_cache_add_page (page_descr_t *page_descr, int pool_idx)
+{
+    page_descr_t *main_descr, *cache_head, *cache_descr;
+
+    main_descr = main_descr_get();
+    cache_head = cache_head_get(cache_idx(page_descr->addr));
+    cache_descr = page_descr_get();
+    if (cache_descr == NULL) {
+        MEMOPS_PRINTF("%s: cannot get cache page\n", __func__);
+        return -1;
+    }
+    cache_descr->nb = pool_idx | (unsigned long)page_descr;
+    cache_descr->prev = cache_head;
+    cache_descr->next = cache_head->next;
+    cache_descr->addr = page_descr->addr;
+    cache_head->next->prev = cache_descr;
+    cache_head->next = cache_descr;
+
+    return 0;
+}
+
+static page_descr_t *page_cache_get_descr (void *addr)
+{
+    page_descr_t *main_descr, *cache_head, *cache_descr;
+
+    main_descr = main_descr_get();
+    cache_head = cache_head_get(cache_idx(addr));
+    for (cache_descr = cache_head->next;
+         cache_descr != cache_head; cache_descr = cache_descr->next) {
+        if (cache_descr->addr == addr) {
+            return cache_descr;
+        }
+    }
+    MEMOPS_PRINTF("%s: cannot get cache page descr\n", __func__);
+
+    return NULL;
+}
+
+static void page_cache_remove_descr (page_descr_t *cache_descr)
+{
+    cache_descr->next->prev = cache_descr->prev;
+    cache_descr->prev->next = cache_descr->next;
+    page_descr_put(cache_descr);
+}
+
+/* Allocation by pool (size <= PAGE_SIZE / 2) */
+static void pool_descr_free (page_descr_t *cache_descr,
+                             page_descr_t *pool_descr)
+{
+    page_put(PAGE(pool_descr->addr), 1);
+    page_cache_remove_descr(cache_descr);
+    pool_descr->next->prev = pool_descr->prev;
+    pool_descr->prev->next = pool_descr->next;
+    page_descr_put(pool_descr);
+}
+
+static void *pool_malloc (int pool_idx)
+{
+    page_descr_t *main_descr, *pool_head, *pool_descr;
+    free_slot_t *first_free, *next_free;
+
+    main_descr = main_descr_get();
+    pool_head = pool_head_get(pool_idx);
+    pool_descr = pool_head->addr;
+    if (pool_descr == NULL || pool_descr->addr == NULL) {
+        pool_descr = descr_find_free(pool_head, NULL);
+        if (pool_descr == NULL) {
+            pool_descr = page_descr_get();
+            if (pool_descr == NULL) {
+                MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__);
+                return NULL;
+            }
+            pool_descr->addr = page_get(1);
+            if (pool_descr->addr == NULL) {
+                MEMOPS_PRINTF("%s: cannot allocate new page\n", __func__);
+                page_descr_put(pool_descr);
+                return NULL;
+            }
+            if (page_cache_add_page(pool_descr, pool_idx) < 0) {
+                MEMOPS_PRINTF("%s: cannot add new page to cache\n", __func__);
+                page_put(pool_descr->addr, 1);
+                page_descr_put(pool_descr);
+                return NULL;
+            }
+            free_slots_init(pool_descr->addr,
+                            1 << (MIN_ELEM_BITS + pool_idx), PAGE_SIZE);
+            pool_descr->nb = 0;
+            pool_descr->prev = pool_head->prev;
+            pool_descr->next = pool_head;
+            pool_head->prev->next = pool_descr;
+            pool_head->prev = pool_descr;
+            pool_head->nb++;
+        }
+        pool_head->addr = pool_descr;
+    }
+    first_free = pool_descr->addr;
+    next_free = first_free->next;
+    //    memset(first_free, 0, 1 << (MIN_ELEM_BITS + pool_idx));
+    pool_descr->addr = next_free;
+    if (pool_descr->nb == 0)
+        pool_head->nb--;
+    pool_descr->nb++;
+
+    return first_free;
+}
+
+unused static void pool_free (page_descr_t *cache_descr, void *area)
+{
+    page_descr_t *pool_head, *pool_descr, *pool_next, *free_pool;
+    free_slot_t *first_free, *next_free;
+    unsigned long size, pool_idx;
+    
+    pool_descr = page_cache_page_descr(cache_descr);
+    first_free = area;
+    next_free = pool_descr->addr;
+    pool_idx = page_cache_pool_idx(cache_descr);
+    size = 1 << (MIN_ELEM_BITS + pool_idx);
+    first_free->next = next_free;
+    pool_descr->addr = first_free;
+    pool_descr->nb--;
+    pool_head = pool_head_get(pool_idx);
+    if (pool_descr->nb == 0) {
+        if (pool_head->addr == pool_descr ||
+            pool_head->addr == NULL ||
+            pool_head->nb > 0)
+            free_pool = descr_find_free(pool_head, pool_descr);
+        else
+            free_pool = pool_head->addr;
+        if (free_pool != NULL) {
+            /* Free page & descriptor */
+            pool_descr_free(cache_descr, pool_descr);
+            pool_head->addr = free_pool;
+        } else {
+            pool_head->addr = pool_descr;
+            pool_head->nb++;
+        }
+    } else if (next_free == NULL) {
+        free_pool = pool_descr;
+        for (pool_descr = pool_head->next;
+             pool_head->nb > 0 && pool_descr != pool_head;
+             pool_descr = pool_next) {
+            pool_next = pool_descr->next;
+            if (pool_descr->nb == 0) {
+                if (pool_head->addr == pool_descr)
+                    pool_head->addr = NULL;
+                cache_descr = page_cache_get_descr(PAGE(pool_descr->addr));
+                if (cache_descr != NULL) {
+                    pool_descr_free(cache_descr, pool_descr);
+                    pool_head->nb--;
+                } else {
+                    /* Incoherency: what to do ? */
+                }
+            }
+        }
+        if (pool_head->addr == NULL)
+            pool_head->addr = free_pool;
+    }
+}
+
+/* Big area management (size > PAGE_SIZE / 2) */
+static void *big_malloc (int nb_pages)
+{
+    page_descr_t *main_descr, *pool_head, *pool_descr;
+
+    main_descr = main_descr_get();
+    pool_head = pool_head_get(POOL_MAX);
+    pool_descr = page_descr_get();
+    if (pool_descr == NULL) {
+        MEMOPS_PRINTF("%s: cannot get pool descr\n", __func__);
+        return NULL;
+    }
+    pool_descr->addr = page_get(nb_pages);
+    if (pool_descr->addr == NULL) {
+        page_descr_put(pool_descr);
+        MEMOPS_PRINTF("%s: cannot get page\n", __func__);
+        return NULL;
+    }
+    if (page_cache_add_page(pool_descr, POOL_MAX) < 0) {
+        page_put(pool_descr->addr, nb_pages);
+        page_descr_put(pool_descr);
+        MEMOPS_PRINTF("%s: cannot get add page to cache\n", __func__);
+        return NULL;
+    }
+    pool_descr->prev = pool_head->prev;
+    pool_descr->next = pool_head;
+    pool_descr->nb = nb_pages;
+    pool_head->prev->next = pool_descr;
+    pool_head->prev = pool_descr;
+
+    return pool_descr->addr;
+}
+
+static void big_free (page_descr_t *cache_descr)
+{
+    page_descr_t *pool_descr;
+
+    pool_descr = page_cache_page_descr(cache_descr);
+    if (pool_descr->addr != NULL && pool_descr->nb != 0) {
+        page_put(pool_descr->addr, pool_descr->nb);
+        pool_descr->next->prev = pool_descr->prev;
+        pool_descr->prev->next = pool_descr->next;
+        page_descr_put(pool_descr);
+        page_cache_remove_descr(cache_descr);
+    } else {
+        MEMOPS_PRINTF("%s: ERROR %p %d\n",
+                      __func__, pool_descr->addr, (int)pool_descr->nb);
+    }
+}
+
+unused static void *big_realloc (page_descr_t *cache_descr, int new_size)
+{
+    void *new_area;
+    page_descr_t *pool_descr;
+    unsigned long new_nb;
+
+    pool_descr = page_cache_page_descr(cache_descr);
+    new_nb = (new_size + PAGE_SIZE - 1) / PAGE_SIZE;
+    if (new_nb == pool_descr->nb) {
+        new_area = cache_descr->addr;
+    } else {
+        new_area = big_malloc(new_size);
+        memcpy(new_area, cache_descr->addr, pool_descr->nb * PAGE_SIZE);
+        big_free(cache_descr);
+    }
+
+    return new_area;
+}
+
+/* Global entry points */
+int page_descrs_init (void)
+{
+    page_descr_t *main_descr, *page_descr, *pool_head, *cache_head;
+    int i;
+
+    /* Allocate first descriptor page */
+    malloc_base = page_get(1);
+    if (malloc_base == NULL) {
+        set_errno(ENOMEM);
+        MEMOPS_PRINTF("%s: cannot get main descriptor\n", __func__);
+        return -1;
+    }
+    /* Init free slots in this page */
+    free_slots_init(malloc_base, sizeof(page_descr_t), PAGE_SIZE);
+    /* Init main descriptor */
+    page_descr = malloc_base;
+    main_descr = main_descr_get();
+    main_descr->addr = page_descr;
+    main_descr->nb = 0;
+    main_descr->next = page_descr;
+    main_descr->prev = page_descr;
+    page_descr->nb = 1;
+    page_descr->addr = page_descr + 2;
+    page_descr->next = main_descr;
+    page_descr->prev = main_descr;
+    /* Init pool lists heads */
+    for (i = 0; i <= POOL_MAX; i++) {
+        pool_head = page_descr_get();
+        if (pool_head == NULL) {
+            page_put(malloc_base, 1);
+            malloc_base = NULL;
+            MEMOPS_PRINTF("%s: cannot get pool descriptor %d\n", __func__, i);
+            return -1;
+        }
+        pool_head->prev = pool_head;
+        pool_head->next = pool_head;
+        pool_head->addr = NULL;
+    }
+    /* Init page caches lists heads */
+    for (i = 0; i < CACHE_MAX; i++) {
+        cache_head = page_descr_get();
+        if (cache_head == NULL) {
+            page_put(malloc_base, 1);
+            malloc_base = NULL;
+            MEMOPS_PRINTF("%s: cannot get page cache descriptor %d\n",
+                          __func__, i);
+            return -1;
+        }
+        cache_head->prev = cache_head;
+        cache_head->next = cache_head;
+    }
+
+    return 0;
+}
+
+static inline int get_pool_idx (size_t size)
+{
+    int pool_idx;
+    
+    pool_idx = 0;
+    for (size /= MIN_ELEM_SIZE; size != 0; size = size / 2)
+        pool_idx++;
+
+    return pool_idx;
+}
+
+#if 1
+void *malloc (size_t size)
+{
+    void *ret;
+    int pool_idx;
+    
+    if (malloc_base == NULL || size == 0) {
+        ret = NULL;
+    } else if (size >= MAX_ELEM_SIZE) {
+        ret = big_malloc((size + PAGE_SIZE - 1) / PAGE_SIZE);
+    } else {
+        if (size <= MIN_ELEM_SIZE)
+            pool_idx = 0;
+        else {
+            pool_idx = get_pool_idx(size);
+        }
+        ret = pool_malloc(pool_idx);
+    }
+    if (ret != NULL)
+        memset(ret, 0, size);
+#if 0
+    memory_dump();
+    printf("%s(%d) => %p\n", __func__, size, ret);
+#endif
+
+    return ret;
+}
+#endif
+
+#if 0
+void free (void *area)
+{
+    page_descr_t *cache_descr;
+    int pool_idx;
+
+    if (malloc_base == NULL || area == NULL)
+        return;
+    cache_descr = page_cache_get_descr(PAGE(area));
+    if (cache_descr != NULL) {
+        pool_idx = page_cache_pool_idx(cache_descr);
+        if (pool_idx == POOL_MAX) {
+            big_free(cache_descr);
+        } else {
+            pool_free(cache_descr, area);
+        }
+    } else {
+        /* Given area is not valid */
+        MEMOPS_PRINTF("ERROR: area to free not found: %p\n", area);
+    }
+}
+#endif
+
+#if 0
+void *realloc (void *area, size_t new_size)
+{
+    void *new_area;
+    page_descr_t *pool_descr, *cache_descr;
+    size_t size;
+    int pool_idx, new_pool_idx;
+
+    if (malloc_base == NULL || new_size == 0) {
+        free(area);
+        return NULL;
+    }
+    if (area == NULL)
+        return malloc(new_size);
+    cache_descr = page_cache_get_descr(PAGE(area));
+    if (cache_descr == NULL) {
+        /* Given area is not valid */
+        return NULL;
+    }
+    pool_idx = page_cache_pool_idx(cache_descr);
+    if (new_size >= MAX_ELEM_SIZE) {
+        new_pool_idx = POOL_MAX;
+        if (pool_idx == POOL_MAX)
+            return big_realloc(cache_descr, new_size);
+    } else {
+        if (new_size <= MIN_ELEM_SIZE)
+            new_pool_idx = 0;
+        else
+            new_pool_idx = get_pool_idx(size);
+        if (pool_idx == new_pool_idx)
+            return area;
+    }
+    /* Common case: alloc, copy & free */
+    if (new_pool_idx == POOL_MAX)
+        new_area = big_malloc((new_size + PAGE_SIZE - 1) / PAGE_SIZE);
+    else
+        new_area = pool_malloc(new_pool_idx);
+    if (new_area == NULL)
+        return NULL;
+    if (pool_idx == POOL_MAX) {
+        pool_descr = page_cache_page_descr(cache_descr);
+        size = pool_descr->nb * PAGE_SIZE;
+    } else {
+        size = MIN_ELEM_SIZE << pool_idx;
+    }
+    memcpy(new_area, area, size);
+    if (pool_idx == POOL_MAX)
+        big_free(cache_descr);
+    else
+        pool_free(cache_descr, area);
+    
+    return new_area;
+}
+#endif
+
+void memory_dump (void)
+{
+#if defined (DEBUG_MEMOPS)
+    page_descr_t *main_descr, *page_descr;
+    page_descr_t *pool_head, *pool_descr, *cache_head, *cache_descr;
+    int i, n;
+
+    main_descr = main_descr_get();
+    /* Dump descriptor pages */
+    printf("Descriptor pages dump: %p max=%d %d pages with no alloc descrs\n",
+           main_descr, (int)(PAGE_SIZE / sizeof(page_descr_t)), (int)main_descr->nb);
+    n = 0;
+    for (page_descr = main_descr->next;
+         page_descr != main_descr; page_descr = page_descr->next) {
+        printf("Descr %d : %p %p used: %d\n",
+               n, page_descr, page_descr->addr, (int)page_descr->nb);
+        n++;
+    }
+    /* Dump pool areas pages */
+    for (i = 0; i < POOL_MAX; i++) {
+        n = 0;
+        pool_head = pool_head_get(i);
+        printf("Pool %d %p\n", i, pool_head);
+        for (pool_descr = pool_head->next;
+             pool_descr != pool_head; pool_descr = pool_descr->next) {
+            printf("Pool %d descr %d : %p %p used: %d size %d free: %p %p\n",
+                   i, n, pool_descr, PAGE(pool_descr->addr), (int)pool_descr->nb,
+                   1 << (MIN_ELEM_BITS + i), pool_descr->addr,
+                   ((free_slot_t *)pool_descr->addr)->next);
+            n++;
+        }
+        printf(" => %d pages allocated\n", n);
+    }
+#if 0
+    /* Dump big area pages */
+    printf("Pool %d\n", POOL_MAX);
+    n = 0;
+    pool_head = pool_head_get(POOL_MAX);
+    for (pool_descr = pool_head->next;
+         pool_descr != pool_head; pool_descr = pool_descr->next) {
+        printf("Pool %d descr %d : %p nb pages: %d\n",
+               POOL_MAX, n, pool_descr->addr, (int)pool_descr->nb);
+        n++;
+    }
+    printf(" => %d pages allocated\n", n);
+    /* Dump page cache */
+    for (i = 0; i < CACHE_MAX; i++) {
+        printf("Page cache 0x____%x___\n", i);
+        n = 0;
+        cache_head = cache_head_get(i);
+        for (cache_descr = cache_head->next;
+             cache_descr != cache_head; cache_descr = cache_descr->next) {
+            pool_descr = page_cache_page_descr(cache_descr);
+            printf("Cache %d descr %d : %p pool: %d descr: %p %p %d\n",
+                   i, n, cache_descr->addr,
+                   (int)page_cache_pool_idx(cache_descr),
+                   pool_descr, pool_descr->addr, (int)pool_descr->nb);
+            n++;
+        }
+        printf(" => %d pages allocated\n", n);
+    }
+#endif
+#endif
+}