1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd
22168404Spjd/*
23168404Spjd * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24168404Spjd * Use is subject to license terms.
25168404Spjd */
26168404Spjd
27168404Spjd#pragma ident	"%Z%%M%	%I%	%E% SMI"
28168404Spjd
29168404Spjd#include <sys/nvpair.h>
30168404Spjd#include <sys/sysmacros.h>
31168404Spjd#if defined(_KERNEL) && !defined(_BOOT)
32168404Spjd#include <sys/varargs.h>
33168404Spjd#else
34168404Spjd#include <stdarg.h>
35168404Spjd#include <strings.h>
36168404Spjd#endif
37168404Spjd
38168404Spjd/*
39168404Spjd * This allocator is very simple.
40168404Spjd *  - it uses a pre-allocated buffer for memory allocations.
41168404Spjd *  - it does _not_ free memory in the pre-allocated buffer.
42168404Spjd *
43168404Spjd * The reason for the selected implemention is simplicity.
44168404Spjd * This allocator is designed for the usage in interrupt context when
45168404Spjd * the caller may not wait for free memory.
46168404Spjd */
47168404Spjd
48168404Spjd/* pre-allocated buffer for memory allocations */
49168404Spjdtypedef struct nvbuf {
50168404Spjd	uintptr_t	nvb_buf;	/* address of pre-allocated buffer */
51168404Spjd	uintptr_t 	nvb_lim;	/* limit address in the buffer */
52168404Spjd	uintptr_t	nvb_cur;	/* current address in the buffer */
53168404Spjd} nvbuf_t;
54168404Spjd
55168404Spjd/*
56168404Spjd * Initialize the pre-allocated buffer allocator. The caller needs to supply
57168404Spjd *
58168404Spjd *   buf	address of pre-allocated buffer
59168404Spjd *   bufsz	size of pre-allocated buffer
60168404Spjd *
61168404Spjd * nv_fixed_init() calculates the remaining members of nvbuf_t.
62168404Spjd */
63168404Spjdstatic int
64168404Spjdnv_fixed_init(nv_alloc_t *nva, va_list valist)
65168404Spjd{
66168404Spjd	uintptr_t base = va_arg(valist, uintptr_t);
67168404Spjd	uintptr_t lim = base + va_arg(valist, size_t);
68168404Spjd	nvbuf_t *nvb = (nvbuf_t *)P2ROUNDUP(base, sizeof (uintptr_t));
69168404Spjd
70168404Spjd	if (base == 0 || (uintptr_t)&nvb[1] > lim)
71168404Spjd		return (EINVAL);
72168404Spjd
73168404Spjd	nvb->nvb_buf = (uintptr_t)&nvb[0];
74168404Spjd	nvb->nvb_cur = (uintptr_t)&nvb[1];
75168404Spjd	nvb->nvb_lim = lim;
76168404Spjd	nva->nva_arg = nvb;
77168404Spjd
78168404Spjd	return (0);
79168404Spjd}
80168404Spjd
81168404Spjdstatic void *
82168404Spjdnv_fixed_alloc(nv_alloc_t *nva, size_t size)
83168404Spjd{
84168404Spjd	nvbuf_t *nvb = nva->nva_arg;
85168404Spjd	uintptr_t new = nvb->nvb_cur;
86168404Spjd
87168404Spjd	if (size == 0 || new + size > nvb->nvb_lim)
88168404Spjd		return (NULL);
89168404Spjd
90168404Spjd	nvb->nvb_cur = P2ROUNDUP(new + size, sizeof (uintptr_t));
91168404Spjd
92168404Spjd	return ((void *)new);
93168404Spjd}
94168404Spjd
95168404Spjd/*ARGSUSED*/
96168404Spjdstatic void
97168404Spjdnv_fixed_free(nv_alloc_t *nva, void *buf, size_t size)
98168404Spjd{
99168404Spjd	/* don't free memory in the pre-allocated buffer */
100168404Spjd}
101168404Spjd
102168404Spjdstatic void
103168404Spjdnv_fixed_reset(nv_alloc_t *nva)
104168404Spjd{
105168404Spjd	nvbuf_t *nvb = nva->nva_arg;
106168404Spjd
107168404Spjd	nvb->nvb_cur = (uintptr_t)&nvb[1];
108168404Spjd}
109168404Spjd
110168404Spjdconst nv_alloc_ops_t nv_fixed_ops_def = {
111168404Spjd	nv_fixed_init,	/* nv_ao_init() */
112168404Spjd	NULL,		/* nv_ao_fini() */
113168404Spjd	nv_fixed_alloc,	/* nv_ao_alloc() */
114168404Spjd	nv_fixed_free,	/* nv_ao_free() */
115168404Spjd	nv_fixed_reset	/* nv_ao_reset() */
116168404Spjd};
117168404Spjd
118168404Spjdconst nv_alloc_ops_t *nv_fixed_ops = &nv_fixed_ops_def;
119