2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
4 * Contributed by Fenghua Yu <Fenghua.Yu@intel.com>
5 * Contributed by Bibo Mao <bibo.mao@intel.com>
6 * Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
8 * This file is part of the ELILO, the EFI Linux boot loader.
10 * ELILO is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * ELILO is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with ELILO; see the file COPYING. If not, write to the Free
22 * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 * Please check out the elilo.txt for complete documentation on how
26 * to use this program.
36 typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t;
38 typedef struct _alloc_entry {
39 struct _alloc_entry *next;
40 struct _alloc_entry *prev;
42 UINTN size; /* bytes for pool, page count for pages */
46 static alloc_entry_t allocs[NALLOC];
47 static alloc_entry_t *free_allocs, *used_allocs;
49 static VOID *kmem_addr;
50 static UINTN kmem_pgcnt;
53 * initializes the free list which is singly linked
60 for(i=0; i < NALLOC-1; i++) {
61 allocs[i].next = allocs+i+1;
63 allocs[i].next = NULL;
72 alloc_add(VOID * addr, UINTN size, alloc_types_t type)
76 /* remove from freelist */
78 free_allocs = free_allocs->next;
81 alloc->next = used_allocs;
86 /* add to used list */
87 if (used_allocs) used_allocs->prev = alloc;
93 alloc(UINTN size, EFI_MEMORY_TYPE type)
98 /* no more free slots */
99 if (free_allocs == NULL) {
100 ERR_PRT((L"allocator: no more slots\n"));
104 if (type == 0) type = EfiLoaderData;
106 status = uefi_call_wrapper(BS->AllocatePool, 3, type, size, &tmp);
107 if (EFI_ERROR(status)) {
108 ERR_PRT((L"allocator: AllocatePool(%d, %d) failed (%r)\n", type, size, status));
111 alloc_add(tmp, size, ALLOC_POOL);
113 DBG_PRT((L"alloc: allocated %d bytes @[" PTR_FMT "-" PTR_FMT "]\n", size, tmp, tmp+size));
119 * no possibility to partially free an allocated group of pages
122 alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr)
125 EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr;
127 /* no more free slots */
128 if (free_allocs == NULL) {
129 ERR_PRT((L"allocator: no more slots\n"));
133 status = uefi_call_wrapper(BS->AllocatePages, 4, where, type , pgcnt, &tmp);
134 if (EFI_ERROR(status)) {
135 VERB_PRT(1, Print(L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));
138 /* XXX: will cause warning on IA-32 */
141 alloc_add(addr, pgcnt, ALLOC_PAGES);
143 DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));
149 * free previously allocated slot
156 /* find allocation record */
157 for(p=used_allocs; p ; p = p->next) {
158 if (p->addr == addr) goto found;
161 VERB_PRT(1, Print(L"allocator: invalid free @ " PTR_FMT "\n", addr));
165 DBG_PRT((L"free: %s @" PTR_FMT " size=%d\n",
166 p->type == ALLOC_POOL ? L"Pool": L"Page",
169 if (p->type == ALLOC_POOL)
170 uefi_call_wrapper(BS->FreePool, 1, addr);
172 uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)addr, p->size);
174 /* remove from used list */
176 p->next->prev = p->prev;
179 p->prev->next = p->next;
181 used_allocs = p->next;
183 /* put back on free list */
184 p->next = free_allocs;
189 * garbage collect all used allocations.
190 * will put the allocator in initial state
199 DBG_PRT((L"free_all %a @ " PTR_FMT "\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));
201 if (used_allocs->type == ALLOC_POOL)
202 uefi_call_wrapper(BS->FreePool, 1, used_allocs->addr);
204 uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);
206 tmp = used_allocs->next;
208 /* put back on free list */
209 used_allocs->next = free_allocs;
210 free_allocs = used_allocs;
217 alloc_kmem_anywhere(VOID **start_addr, UINTN pgcnt)
220 if ((tmp = alloc_pages(pgcnt, EfiLoaderData, AllocateAnyPages, *start_addr)) == 0) return -1;
230 alloc_kmem(VOID *start_addr, UINTN pgcnt)
232 if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1;
234 kmem_addr = start_addr;
244 DBG_PRT((L"free_kmem before (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt));
246 if (kmem_addr && kmem_pgcnt != 0) {
252 DBG_PRT((L"free_kmem after (" PTR_FMT ", %d)\n", kmem_addr, kmem_pgcnt));
257 free_all_memory(VOID)