alloc.c

来自「EFI(Extensible Firmware Interface)是下一代BI」· C语言 代码 · 共 241 行

C
241
字号
/* *  Copyright (C) 2001-2003 Hewlett-Packard Co. *	Contributed by Stephane Eranian <eranian@hpl.hp.com> * * This file is part of the ELILO, the EFI Linux boot loader. * *  ELILO is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. * *  ELILO 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 ELILO; see the file COPYING.  If not, write to the Free *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA *  02111-1307, USA. * * Please check out the elilo.txt for complete documentation on how * to use this program. */#include <efi.h>#include <efilib.h>#include "elilo.h"#define NALLOC	512typedef enum { ALLOC_POOL, ALLOC_PAGES } alloc_types_t;typedef struct _alloc_entry {	struct _alloc_entry	*next;	struct _alloc_entry	*prev;	VOID			*addr;	UINTN			size; /* bytes for pool, page count for pages */	alloc_types_t		type;} alloc_entry_t;static alloc_entry_t allocs[NALLOC];static alloc_entry_t *free_allocs, *used_allocs;static VOID *kmem_addr;static UINTN kmem_pgcnt;/* * initializes the free list which is singly linked */INTNalloc_init(VOID){	UINTN i;	for(i=0; i < NALLOC-1; i++) {		allocs[i].next = allocs+i+1;	}	allocs[i].next = NULL;	free_allocs = allocs;	used_allocs = NULL;	return 0;}static VOIDalloc_add(VOID * addr, UINTN size, alloc_types_t type){	alloc_entry_t *alloc;	/* remove from freelist */	alloc 	    = free_allocs;	free_allocs = free_allocs->next;		alloc->prev = NULL;	alloc->next = used_allocs;	alloc->addr = addr;	alloc->type = type;	alloc->size = size;	/* add to used list */	if (used_allocs) used_allocs->prev = alloc;	used_allocs = alloc;}VOID *alloc(UINTN size, EFI_MEMORY_TYPE type){	EFI_STATUS status;	VOID *tmp = 0;	/* no more free slots */	if (free_allocs == NULL) {        	ERR_PRT((L"allocator:  no more slots\n"));		return NULL;	}	if (type == 0) type = EfiLoaderData;	status = BS->AllocatePool (type, size, &tmp);    	if (EFI_ERROR(status)) {        	ERR_PRT((L"allocator: AllocatePool(%d, %d, 0x%x) failed (%r)\n", type, size, status));		return NULL;    	}	alloc_add(tmp, size, ALLOC_POOL);        DBG_PRT((L"alloc: allocated %d bytes @[0x%lx-0x%lx]\n", size, tmp, tmp+size));	return tmp;}/* *  no possibility to partially free an allocated group of pages */VOID *alloc_pages(UINTN pgcnt, EFI_MEMORY_TYPE type, EFI_ALLOCATE_TYPE where, VOID *addr){	EFI_STATUS status;	EFI_PHYSICAL_ADDRESS tmp = (EFI_PHYSICAL_ADDRESS)addr;	/* no more free slots */	if (free_allocs == NULL) {        	ERR_PRT((L"allocator:  no more slots\n"));		return NULL;	}	status = BS->AllocatePages(where, type , pgcnt, &tmp);    	if (EFI_ERROR(status)) {        	ERR_PRT((L"allocator: AllocatePages(%d, %d, %d, 0x%lx) failed (%r)\n", where, type, pgcnt, tmp, status));		return NULL;    	}	/* XXX: will cause warning on IA-32 */	addr = (VOID *)tmp;	alloc_add(addr, pgcnt, ALLOC_PAGES);        DBG_PRT((L"allocator: allocated %d pages @0x%lx\n", pgcnt, tmp));	return addr;}/* * free previously allocated slot */VOIDfree(VOID *addr){	alloc_entry_t *p;	/* find allocation record */	for(p=used_allocs; p ; p = p->next) {		if (p->addr == addr) goto found;	}	/* not found */        ERR_PRT((L"allocator: invalid free @ 0x%lx\n", addr));	return;	found:        DBG_PRT((L"free: %s @0x%lx size=%ld\n", 		p->type == ALLOC_POOL ? L"Pool": L"Page", 		addr, p->size));	if (p->type == ALLOC_POOL) 		BS->FreePool(addr);	else		BS->FreePages((EFI_PHYSICAL_ADDRESS)addr, p->size);	/* remove from used list */	if (p->next) 		p->next->prev = p->prev;			if (p->prev) 		p->prev->next = p->next;	else		used_allocs = p->next;	/* put back on free list */	p->next     = free_allocs;	free_allocs = p;}/* * garbage collect all used allocations. * will put the allocator in initial state  */VOIDfree_all(VOID){	alloc_entry_t *tmp;	while(used_allocs) {		DBG_PRT((L"free_all %a @ 0x%lx\n", used_allocs->type == ALLOC_POOL ? "pool" : "pages", used_allocs->addr));			if (used_allocs->type == ALLOC_POOL)			BS->FreePool(used_allocs->addr);		else			BS->FreePages((EFI_PHYSICAL_ADDRESS)used_allocs->addr, used_allocs->size);		tmp = used_allocs->next;		/* put back on free list */		used_allocs->next = free_allocs;		free_allocs = used_allocs;		used_allocs = tmp;	}}INTNalloc_kmem(VOID *start_addr, UINTN pgcnt){	if (alloc_pages(pgcnt, EfiLoaderData, AllocateAddress, start_addr) == 0) return -1;	kmem_addr  = start_addr;	kmem_pgcnt = pgcnt;	return 0;}VOIDfree_kmem(VOID){	DBG_PRT((L"free_kmem before (%lx, %ld)\n", kmem_addr, kmem_pgcnt));	if (kmem_addr && kmem_pgcnt != 0) {		free(kmem_addr);		kmem_addr  = NULL;		kmem_pgcnt = 0;	}	DBG_PRT((L"free_kmem after (%lx, %ld)\n", kmem_addr, kmem_pgcnt));}VOIDfree_all_memory(VOID){	free_all();	free_kmem();}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?