sun4x_standalloc.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/bootconf.h>
#define NIL 0
#ifdef DEBUG
static int resalloc_debug = 1;
#else /* DEBUG */
static int resalloc_debug = 0;
#endif /* DEBUG */
extern void reset_alloc(void);
extern void alloc_segment(caddr_t);
extern int pagesize;
/*
* OBP sets up a 1:1 mapping of virtual to physical in the range 8KB-10MB. The
* standalone is free to use any or all of this during its lifetime.
* Unfortunately, some platforms (Serengeti and LW8) can't use the full range.
* See 4799331 for more details. Limited platforms can use up to
* MAPPEDMEM_MINTOP; everyone else can use up to MAPPEDMEM_FULLTOP.
* resalloc_init makes the determination as to how much the machine being booted
* can use.
*
* But wait! There's more! resalloc handles three types of allocations: Two
* flavors of RES_BOOTSCRATCH (RES_BOOTSCRATCH and RES_BOOTSCRATCH_NOFAIL), and
* one of RES_CHILDVIRT. RES_CHILDVIRT is handled by prom_alloc, and is boring.
* We handle RES_BOOTSCRATCH allocations ourselves using the portion of the 1:1
* range not consumed by boot. The unconsumed range is subdivided into two
* portions - the general area from top_resvmem to top_bootmem and the reserved
* area from above memlistpage to top_resvmem. Both RES_BOOTSCRATCH flavors are
* satisfied by the general area until said area is exhausted, at which point
* RES_BOOTSCRATCH allocations return failure. RES_BOOTSCRATCH_NOFAIL
* allocations can't fail, so we'll try to satisfy them from the reserved area
* if the general area is full. If we still can't satisfy the nofail
* allocation, we'll call prom_panic.
*
* This whole boot memory allocation thing needs some serious rethinking.
*
* Memory layout:
*
* |-------| top_bootmem
* | | } MAPPEDMEM_FULLTOP (only on non-serengeti, lw8)
* | | } MAPPEDMEM_MINTOP
* |-------| top_resvmem/scratchmemp
* | | } MAPPEDMEM_RESERVE
* |-------| scratchresvp
* | | } one page
* |-------| memlistpage (at roundup(_end, pagesize))
* |-------| _end
* | boot |
* : :
*
*/
static int
{
dnode_t n = prom_rootnode();
return (-1);
return (0);
}
static caddr_t
{
caddr_t v;
int i;
/* find first region which fits */
continue;
if (i == N_FREELIST) {
dprintf("boot: failed to allocate %lu bytes from scratch "
"memory\n", bytes);
return (NULL);
}
v = free_addr[i];
(void *)v);
return (v);
}
/*
* This routine will find the next PAGESIZE chunk in the
* low MAPPEDMEM_MINTOP. 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.
*/
static caddr_t
{
caddr_t v;
if (!numpages)
return (0);
/* We know the page is mapped because the 1st MAPPEDMEM_MINTOP is 1:1 */
v = scratchmemp;
scratchmemp += bytes;
return (v);
}
/*
* If we run out of scratch memory, look in the freelist
*/
return (v);
/*
* Try really hard for allocations that can't fail. Look in the area
* that we've reserved for them.
*/
if (type == RES_BOOTSCRATCH_NOFAIL) {
v = scratchresvp;
scratchresvp += bytes;
dprintf("using %lu bytes of reserved mem (%lu left)\n",
return (v);
} else {
printf("boot: failed to allocate %lu bytes from "
"reserved scratch memory\n", bytes);
prom_panic("boot: scratch memory overflow.\n");
}
}
return (NULL);
}
void
resalloc_init(void)
{
char iarch[128];
dprintf("boot: resalloc_init: failed to read iarch\n");
return;
}
/*
* but we don't have the ability to check for the firmware version here.
*/
return;
dprintf("boot: resalloc_init: boosted top_bootmem to %p\n",
(void *)top_bootmem);
}
{
long pmap = 0;
if (memlistpage == (caddr_t)0)
reset_alloc();
if (bytes == 0)
return ((caddr_t)0);
/* extend request to fill a page */
switch (type) {
/*
* even V2 PROMs never bother to indicate whether the
* first MAPPEDMEM_MINTOP is taken or not. So we do it all here.
* Smart PROM or no smart PROM.
*/
case RES_BOOTSCRATCH:
case RES_BOOTSCRATCH_NOFAIL:
if (resalloc_debug) {
}
return (vaddr);
/*NOTREACHED*/
case RES_CHILDVIRT:
return (vaddr);
printf("Alloc of 0x%lx bytes at 0x%p refused.\n",
return ((caddr_t)0);
/*NOTREACHED*/
default:
printf("Bad resurce type\n");
return ((caddr_t)0);
}
}
#ifdef lint
#endif /* lint */
void
reset_alloc(void)
{
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 MAPPEDMEM_MINTOP.
* In this way, the kernel can just snarf it all when
* when it is ready, and not worry about snarfing lists.
*/
/*
* This next is for scratch memory only
* We only need 1 page in memlistpage for now
*/
}
void
{
int i;
/* make sure this is boot scratch memory */
switch (type) {
case RES_BOOTSCRATCH:
return;
break;
default:
return;
}
/*
* Add this to the end of the free list
* NOTE: This relies on the fact that KRTLD calls BOP_FREE
* from largest to smallest chunks.
*/
for (i = 0; i < N_FREELIST && free_size[i]; i++)
;
if (i == N_FREELIST)
return;
}