Files
Arquivotheca.Solaris-2.5/stand/lib/common/standalloc.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

286 lines
6.6 KiB
C
Executable File

/*
* Copyright (c) 1991-1994 Sun Microsystems, Inc.
*/
#ident "@(#)standalloc.c 1.40 95/09/25 SMI"
#include <sys/types.h>
#include <sys/saio.h>
#include <sys/sysmacros.h>
#include <sys/promif.h>
#include <sys/bootconf.h>
#define NIL 0
#ifdef DEBUG
static int resalloc_debug = 1;
#else DEBUG
static int resalloc_debug = 0;
#endif DEBUG
#define dprintf if (resalloc_debug) printf
extern struct memlist *vfreelistp, *pfreelistp;
extern int insert_node(struct memlist **list,
struct memlist *request);
extern struct memlist *get_min_node(struct memlist *l, u_longlong_t lo,
u_int size);
extern void reset_alloc(void);
extern caddr_t get_low_vpage(int n);
extern void alloc_segment(caddr_t v);
extern caddr_t get_hi_ppage(void);
extern void map_child(caddr_t v, caddr_t p);
extern caddr_t resalloc(enum RESOURCES type,
unsigned bytes, caddr_t virthint, int align);
extern void print_memlist(struct memlist *av);
extern caddr_t top_bootmem;
extern caddr_t magic_phys;
caddr_t memlistpage;
caddr_t le_page;
caddr_t ie_page;
caddr_t scratchmemp;
extern int pagesize;
/*
* This routine should be called get_a_page().
* It allocates from the appropriate entity one or
* more pages and maps them in.
* Note that there is no resfree() function.
* This then assumes that the standalones cannot free
* any pages which have been allocated and mapped.
*/
caddr_t
kern_resalloc(caddr_t virthint, u_int size, int align)
{
if (virthint != 0)
return (resalloc(RES_CHILDVIRT, size, virthint, align));
else {
return (resalloc(RES_BOOTSCRATCH, size, NULL, NULL));
}
}
caddr_t
resalloc(enum RESOURCES type, unsigned bytes, caddr_t virthint, int align)
{
caddr_t vaddr;
long pmap = 0;
if (memlistpage == (caddr_t)0)
reset_alloc();
if (bytes == 0)
return ((caddr_t)0);
/* extend request to fill a page */
bytes = roundup(bytes, pagesize);
dprintf("resalloc: bytes = %x\n", bytes);
switch (type) {
/*
* even V2 PROMs never bother to indicate whether the
* first MAGIC_PHYS is taken or not. So we do it all here.
* Smart PROM or no smart PROM.
*/
case RES_BOOTSCRATCH:
vaddr = get_low_vpage(bytes/pagesize);
if (resalloc_debug) {
dprintf("vaddr = %x, paddr = %x\n", vaddr, ptob(pmap));
print_memlist(vfreelistp);
print_memlist(pfreelistp);
}
return (vaddr);
/*NOTREACHED*/
break;
case RES_CHILDVIRT:
vaddr = (caddr_t) prom_alloc(virthint, bytes, align);
if (vaddr == (caddr_t)virthint)
return (vaddr);
#ifdef sparc
if (prom_getversion() <= 0) {
struct memlist a;
caddr_t v;
/*
* First we need to find, allocate, and map
* the segments corresponding to the
* virthint+size. We also map the
* pages within that range.
* We don't really care if the pages
* were previously mapped or not because
* we rely upon the integrity of our own
* memlists.
*/
for (v = virthint; v < virthint + bytes;
v += pagesize) {
caddr_t p;
/*
* we put the virtual
* addr on the list
*/
a.address = (u_int)v;
a.size = pagesize;
a.next = a.prev = NIL;
if (insert_node(&vfreelistp, &a) == 0)
prom_panic("Cannot fill request.\n");
/*
* ...and the physical
*/
p = get_hi_ppage();
a.address = (u_int)p;
a.size = pagesize;
a.next = a.prev = NIL;
if (insert_node(&pfreelistp, &a) == 0)
prom_panic("Cannot fill request.\n");
/* Now map them together */
map_child(v, p);
}
if (resalloc_debug) {
dprintf("virthint = %x\n", virthint);
print_memlist(vfreelistp);
print_memlist(pfreelistp);
}
return (virthint);
} else {
#endif
printf("Alloc of 0x%x bytes at 0x%x refused.\n",
bytes, virthint);
return ((caddr_t)0);
#ifdef sparc
}
#endif
/*NOTREACHED*/
break;
default:
printf("Bad resurce type\n");
return ((caddr_t)0);
}
}
void
reset_alloc()
{
extern char _end[];
/* Cannot be called multiple times */
if (memlistpage != (caddr_t)0)
return;
/*
* Due to kernel history and ease of programming, we
* want to keep everything private to /boot BELOW MAGIC_PHYS.
* In this way, the kernel can just snarf it all when
* when it is ready, and not worry about snarfing lists.
*/
memlistpage = (caddr_t)roundup((u_int)_end, pagesize);
/*
* This next is for scratch memory only
* We only need 1 page in memlistpage for now
*/
scratchmemp = (caddr_t)(memlistpage + pagesize);
le_page = (caddr_t)(scratchmemp + pagesize);
ie_page = (caddr_t)(le_page + pagesize);
bzero(memlistpage, pagesize);
bzero(scratchmemp, pagesize);
dprintf("memlistpage = %x\n", memlistpage);
dprintf("le_page = %x\n", le_page);
}
/*
* This routine will find the next PAGESIZE chunk in the
* low MAGIC_PHYS. It is analogous to valloc(). It is only for boot
* scratch memory, because child scratch memory goes up in
* the the high memory. We just need to verify that the
* pages are on the list. The calling routine will actually
* remove them.
*/
caddr_t
get_low_vpage(int numpages)
{
caddr_t v;
#ifdef i386
extern int expand_scratch(int size);
expand_scratch(numpages * pagesize); /* bootscratch: switch arenas? */
#endif
v = scratchmemp;
if (!numpages)
return (0);
/* We know the page is mapped because the 1st MAGIC_PHYS is 1:1 */
scratchmemp += (numpages * pagesize);
/* keep things from getting out of hand */
if (scratchmemp >= top_bootmem)
prom_panic("Boot: scratch memory overflow.\n");
return (v);
}
/*
* This routine will allocate a phys page from our
* list of ones known to be unallocated. Death and
* destruction shall befall those programs which do not
* register their memory usage. They will most likely
* obtain double mappings.
*/
caddr_t
get_hi_ppage(void)
{
struct memlist *node;
node = NIL;
if (pfreelistp == NIL)
prom_panic("No physmemory list.\n");
/*
* Since physmem gets crowded below MAGIC_PHYS, we start
* searching above that magic spot all the time for
* phys pages for a child.
*/
node = get_min_node(pfreelistp, (u_longlong_t)magic_phys, pagesize);
if (node == NIL)
prom_panic("get_hi_ppage(): Cannot find link in range.\n");
/*
* It is best to let the calling routine take
* the node off the freelist.
*/
return ((caddr_t)MAX(node->address, (int) magic_phys));
}
int
get_progmemory(caddr_t vaddr, u_int size, int align)
{
u_int n;
/*
* if the vaddr given is not a mult of PAGESIZE,
* then we rounddown to a page, but keep the same
* ending addr.
*/
n = (u_int)vaddr & (pagesize - 1);
if (n) {
vaddr -= n;
size += n;
}
dprintf("get_progmem: requesting %x bytes at %x\n", size, vaddr);
if (resalloc(RES_CHILDVIRT, size, vaddr, align) != vaddr)
return (-1);
return (0);
}