#include <sys/types.h>
#include <sys/saio.h>
#include <sys/sysmacros.h>
#include <sys/promif.h>
#include <sys/bootconf.h>
#include <sys/salib.h>
#define NIL 0
#ifdef DEBUG
static int resalloc_debug = 1;
#else
static int resalloc_debug = 0;
#endif
#define dprintf if (resalloc_debug) printf
extern struct memlist *vfreelistp, *pfreelistp;
extern void reset_alloc(void);
extern void alloc_segment(caddr_t);
extern caddr_t memlistpage;
caddr_t le_page;
caddr_t ie_page;
caddr_t scratchmemp;
extern int pagesize;
#define N_FREELIST 20
static size_t free_size[N_FREELIST];
static caddr_t free_addr[N_FREELIST];
#define MAPPEDMEM_RESERVE (512*1024)
#define MAPPEDMEM_MINTOP (caddr_t)(6*1024*1024)
#define MAPPEDMEM_FULLTOP (caddr_t)(10*1024*1024)
static caddr_t top_bootmem = MAPPEDMEM_MINTOP;
static caddr_t top_resvmem, scratchresvp;
int is_sg;
caddr_t sg_addr;
size_t sg_len;
static int
impl_name(char *buf, size_t bufsz)
{
pnode_t n = prom_rootnode();
size_t len = prom_getproplen(n, "name");
if (len == 0 || len >= bufsz)
return (-1);
(void) prom_getprop(n, "name", buf);
buf[len] = '\0';
return (0);
}
static caddr_t
vpage_from_freelist(size_t bytes)
{
caddr_t v;
int i;
for (i = 0; i < N_FREELIST && free_size[i] < bytes; i++)
continue;
if (i == N_FREELIST) {
dprintf("boot: failed to allocate %lu bytes from scratch "
"memory\n", bytes);
return (NULL);
}
v = free_addr[i];
free_addr[i] += bytes;
free_size[i] -= bytes;
dprintf("reuse freed temp scratch: bytes = %lu at %p\n", bytes,
(void *)v);
return (v);
}
static caddr_t
get_low_vpage(size_t numpages, enum RESOURCES type)
{
size_t bytes;
caddr_t v;
if (!numpages)
return (0);
bytes = numpages * pagesize;
if (scratchmemp + bytes <= top_bootmem) {
v = scratchmemp;
scratchmemp += bytes;
return (v);
}
if ((v = vpage_from_freelist(bytes)) != NULL)
return (v);
if (type == RES_BOOTSCRATCH_NOFAIL) {
if (scratchresvp + bytes <= top_resvmem) {
v = scratchresvp;
scratchresvp += bytes;
dprintf("using %lu bytes of reserved mem (%lu left)\n",
bytes, top_resvmem - scratchresvp);
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];
if (impl_name(iarch, sizeof (iarch)) < 0) {
dprintf("boot: resalloc_init: failed to read iarch\n");
return;
}
dprintf("boot: resalloc_init: got iarch %s\n", iarch);
if (strcmp(iarch, "SUNW,Sun-Fire") == 0 ||
strcmp(iarch, "SUNW,Netra-T12") == 0) {
is_sg = 1;
sg_addr = MAPPEDMEM_MINTOP;
sg_len = MAPPEDMEM_FULLTOP - MAPPEDMEM_MINTOP;
if (prom_alloc(sg_addr, sg_len, 1) != sg_addr)
prom_panic("can't extend sg bootmem");
}
top_bootmem = MAPPEDMEM_FULLTOP;
dprintf("boot: resalloc_init: boosted top_bootmem to %p\n",
(void *)top_bootmem);
}
caddr_t
resalloc(enum RESOURCES type, size_t 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);
bytes = roundup(bytes, pagesize);
dprintf("resalloc: bytes = %lu\n", bytes);
switch (type) {
case RES_BOOTSCRATCH:
case RES_BOOTSCRATCH_NOFAIL:
vaddr = get_low_vpage((bytes/pagesize), type);
if (resalloc_debug) {
dprintf("vaddr = %p, paddr = %lx\n", (void *)vaddr,
ptob(pmap));
print_memlist(vfreelistp);
print_memlist(pfreelistp);
}
return (vaddr);
case RES_CHILDVIRT:
vaddr = (caddr_t)prom_alloc(virthint, bytes, align);
if (vaddr == (caddr_t)virthint)
return (vaddr);
printf("Alloc of 0x%lx bytes at 0x%p refused.\n",
bytes, (void *)virthint);
return ((caddr_t)0);
default:
printf("Bad resurce type\n");
return ((caddr_t)0);
}
}
#ifdef lint
static char _end[1];
#endif
void
reset_alloc(void)
{
extern char _end[];
if (memlistpage != (caddr_t)0)
return;
memlistpage = (caddr_t)roundup((uintptr_t)_end, pagesize);
scratchresvp = (caddr_t)(memlistpage + pagesize);
scratchmemp = top_resvmem = scratchresvp + MAPPEDMEM_RESERVE;
le_page = (caddr_t)(scratchmemp + pagesize);
ie_page = (caddr_t)(le_page + pagesize);
bzero(memlistpage, pagesize);
bzero(scratchmemp, pagesize);
dprintf("memlistpage = %p\n", (void *)memlistpage);
dprintf("le_page = %p\n", (void *)le_page);
}
void
resfree(enum RESOURCES type, caddr_t virtaddr, size_t size)
{
int i;
switch (type) {
case RES_BOOTSCRATCH:
if (virtaddr + size > top_bootmem)
return;
break;
default:
return;
}
for (i = 0; i < N_FREELIST && free_size[i]; i++)
;
if (i == N_FREELIST)
return;
free_size[i] = size;
free_addr[i] = virtaddr;
}