Files
retrobsd/sys/kernel/subr_rmap.c
Serge Vakulenko 585773955b Fix include paths in the kernel sources.
Max32 kernel successfully compiled with kconfig utility.
2015-08-31 00:21:41 -07:00

233 lines
7.0 KiB
C

/*
* Copyright (c) 1986 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/map.h>
#include <sys/vm.h>
/*
* Resource map handling routines.
*
* A resource map is an array of structures each of which describes a
* segment of the address space of an available resource. The segments
* are described by their base address and length, and sorted in address
* order. Each resource map has a fixed maximum number of segments
* allowed. Resources are allocated by taking part or all of one of the
* segments of the map.
*
* Returning of resources will require another segment if the returned
* resources are not adjacent in the address space to an existing segment.
* If the return of a segment would require a slot which is not available,
* then one of the resource map segments is discarded after a warning is
* printed.
*
* Returning of resources may also cause the map to collapse by coalescing
* two existing segments and the returned space into a single segment. In
* this case the resource map is made smaller by copying together to fill
* the resultant gap.
*
* N.B.: the current implementation uses a dense array and does not admit
* the value ``0'' as a legal address or size, since that is used as a
* delimiter.
*/
/*
* Allocate 'size' units from the given map. Return the base of the
* allocated space. In a map, the addresses are increasing and the
* list is terminated by a 0 size.
*
* Algorithm is first-fit.
*/
size_t
malloc (mp, size)
struct map *mp;
register size_t size;
{
register struct mapent *bp, *ep;
size_t addr;
if (! size)
panic ("malloc: size = 0");
/*
* Search for a piece of the resource map which has enough
* free space to accomodate the request.
*/
for (bp = mp->m_map; bp->m_size; ++bp)
if (bp->m_size >= size) {
/*
* Allocate from the map. If we allocated the entire
* piece, move the rest of the map to the left.
*/
addr = bp->m_addr;
bp->m_size -= size;
if (bp->m_size)
bp->m_addr += size;
else for (ep = bp;; ++ep) {
*ep = *++bp;
if (!bp->m_size)
break;
}
return(addr);
}
/* no entries big enough */
return 0;
}
/*
* Free the previously allocated size units at addr into the specified
* map. Sort addr into map and combine on one or both ends if possible.
*/
void
mfree (mp, size, addr)
struct map *mp;
size_t size;
register size_t addr;
{
register struct mapent *bp, *ep;
struct mapent *start;
if (! size)
return;
/* the address must not be 0, or the protocol has broken down. */
if (! addr)
panic ("mfree: addr = 0");
/*
* locate the piece of the map which starts after the
* returned space (or the end of the map).
*/
bp = mp->m_map;
/* printf ("mfree (size=%u, addr=%u) m_map = %08x\n", size, addr, bp); */
while (bp->m_size && bp->m_addr <= addr) {
/*printf ("skip m_map[%d]: m_addr %u <= addr %u\n", bp - mp->m_map, bp->m_addr, addr);*/
++bp;
}
/* if there is a piece on the left abutting us, combine with it. */
ep = bp - 1;
if (bp != mp->m_map && ep->m_addr + ep->m_size >= addr) {
#ifdef DIAGNOSTIC
/* any overlap is an internal error */
if (ep->m_addr + ep->m_size > addr)
panic("mfree overlap #1");
#endif
/* add into piece on the left by increasing its size. */
ep->m_size += size;
/*
* if the combined piece abuts the piece on the right now,
* compress it in also, by shifting the remaining pieces
* of the map over.
*/
if (bp->m_size && addr + size >= bp->m_addr) {
#ifdef DIAGNOSTIC
if (addr + size > bp->m_addr)
panic("mfree overlap #2");
#endif
ep->m_size += bp->m_size;
do {
*++ep = *++bp;
} while (bp->m_size);
}
return;
}
/* if doesn't abut on the left, check for abutting on the right. */
if (bp->m_size && addr + size >= bp->m_addr) {
#ifdef DIAGNOSTIC
if (addr + size > bp->m_addr)
panic("mfree overlap #3");
#endif
bp->m_addr = addr;
bp->m_size += size;
return;
}
/* doesn't abut. Make a new entry and check for map overflow. */
for (start = bp; bp->m_size; ++bp);
if (++bp > mp->m_limit)
/*
* too many segments; if this happens, the correct fix
* is to make the map bigger; you can't afford to lose
* chunks of the map. If you need to implement recovery,
* use the above "for" loop to find the smallest entry
* and toss it.
*/
printf("%s: overflow, lost %u clicks at 0%o\n",
mp->m_name, size, addr);
else {
for (ep = bp - 1; ep >= start; *bp-- = *ep--);
start->m_addr = addr;
start->m_size = size;
}
}
/*
* Allocate resources for the three segments of a process (data, stack
* and u.), attempting to minimize the cost of failure part-way through.
* Since the segments are located successively, it is best for the sizes
* to be in decreasing order; generally, data, stack, then u. will be
* best. Returns NULL on failure, address of u. on success.
*/
size_t
malloc3 (mp, d_size, s_size, u_size, a)
struct map *mp;
size_t d_size, s_size, u_size;
size_t a[3];
{
register struct mapent *bp, *remap;
register int next;
struct mapent *madd[3];
size_t sizes[3];
int found;
sizes[0] = d_size;
sizes[1] = s_size;
sizes[2] = u_size;
/*
* note, this has to work for d_size and s_size of zero,
* since init() comes in that way.
*/
madd[0] = madd[1] = madd[2] = remap = NULL;
for (found = 0, bp = mp->m_map; bp->m_size; ++bp)
for (next = 0; next < 3; ++next)
if (!madd[next] && sizes[next] <= bp->m_size) {
madd[next] = bp;
bp->m_size -= sizes[next];
if (!bp->m_size && !remap)
remap = bp;
if (++found == 3)
goto resolve;
}
/* couldn't get it all; restore the old sizes, try again */
for (next = 0; next < 3; ++next)
if (madd[next])
madd[next]->m_size += sizes[next];
return 0;
resolve:
/* got it all, update the addresses. */
for (next = 0; next < 3; ++next) {
bp = madd[next];
a[next] = bp->m_addr;
bp->m_addr += sizes[next];
}
/* remove any entries of size 0; addr of 0 terminates */
if (remap) {
for (bp = remap + 1;; ++bp) {
if (bp->m_size || !bp->m_addr) {
*remap++ = *bp;
if (!bp->m_addr)
break;
}
}
}
return(a[2]);
}