2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * This file is part of the ELILO, the EFI Linux boot loader.
7 * ELILO is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * ELILO is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with ELILO; see the file COPYING. If not, write to the Free
19 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 * Please check out the elilo.txt for complete documentation on how
23 * to use this program.
33 typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t;
35 typedef struct _alloc_entry {
36 struct _alloc_entry *next;
37 struct _alloc_entry *prev;
39 UINTN size; /* bytes for pool, page count for pages */
43 static alloc_entry_t allocs[NALLOC];
44 static alloc_entry_t *free_allocs, *used_allocs;
46 static VOID *kmem_addr;
47 static UINTN kmem_pgcnt;
50 * initializes the free list which is singly linked
57 for(i=0; i < NALLOC-1; i++) {
58 allocs[i].next = allocs+i+1;
60 allocs[i].next = NULL;
69 alloc_add(VOID * addr, UINTN size, alloc_types_t type)
73 /* remove from freelist */
75 free_allocs = free_allocs->next;
78 alloc->next = used_allocs;
83 /* add to used list */
84 if (used_allocs) used_allocs->prev = alloc;
90 alloc(UINTN size, EFI_MEMORY_TYPE type)
95 /* no more free slots */
96 if (free_allocs == NULL) {
97 ERR_PRT((L"allocator: no more slots\n"));
101 if (type == 0) type = EfiLoaderData;
103 status = BS->AllocatePool (type, size, &tmp);
104 if (EFI_ERROR(status)) {
105 ERR_PRT((L"allocator: AllocatePool(%d, %d, 0x%x) failed (%r)\n", type, size, status));
108 alloc_add(tmp, size, ALLOC_POOL);
110 DBG_PRT((L"alloc: allocated %d bytes @[0x%lx-0x%lx]\n", size, tmp, tmp+size));
116 * no possibility to partially free an allocated group of pages
119 alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr)
122 EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr;
124 /* no more free slots */
125 if (free_allocs == NULL) {
126 ERR_PRT((L"allocator: no more slots\n"));
130 status = BS->AllocatePages(where, type , pgcnt, &tmp);
131 if (EFI_ERROR(status)) {
132 VERB_PRT(1, (L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
135 /* XXX: will cause warning on IA-32 */
138 alloc_add(addr, pgcnt, ALLOC_PAGES);
140 DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));
146 * free previously allocated slot
153 /* find allocation record */
154 for(p=used_allocs; p ; p = p->next) {
155 if (p->addr == addr) goto found;
158 VERB_PRT(1, (L"allocator: invalid free @ 0x%lx\n", addr));
161 DBG_PRT((L"free: %s @0x%lx size=%ld\n",
162 p->type == ALLOC_POOL ? L"Pool": L"Page",
165 if (p->type == ALLOC_POOL)
168 BS->FreePages((EFI_PHYSICAL_ADDRESS)addr, p->size);
170 /* remove from used list */
172 p->next->prev = p->prev;
175 p->prev->next = p->next;
177 used_allocs = p->next;
179 /* put back on free list */
180 p->next = free_allocs;
185 * garbage collect all used allocations.
186 * will put the allocator in initial state
195 DBG_PRT((L"free_all %a @ 0x%lx\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));
197 if (used_allocs->type == ALLOC_POOL)
198 BS->FreePool(used_allocs->addr);
200 BS->FreePages((EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
202 tmp = used_allocs->next;
204 /* put back on free list */
205 used_allocs->next = free_allocs;
206 free_allocs = used_allocs;
213 alloc_kmem(VOID *start_addr, UINTN pgcnt)
215 if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1;
217 kmem_addr = start_addr;
226 DBG_PRT((L"free_kmem before (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
227 if (kmem_addr && kmem_pgcnt != 0) {
232 DBG_PRT((L"free_kmem after (%lx, %ld)\n", kmem_addr, kmem_pgcnt));
236 free_all_memory(VOID)