/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/types.h>
#include <sys/promif.h>
#include <sys/bootconf.h>
#include <sys/salib.h>
#include <sys/boot.h>
#include "boot_plat.h"

char *v2path, *kernname, *systype;
char *my_own_name = "boot";
char v2args_buf[V2ARGS_BUF_SZ];
char *v2args = v2args_buf;
char *mfg_name;
char *impl_arch_name;
char *bootp_response;
char *module_path;
int  cache_state;
uint64_t memlistextent;		/* replacement for old member of bootops */

/*  These are the various memory lists */
struct memlist	*pfreelistp, /* physmem available */
		*vfreelistp, /* virtmem available */
		*pinstalledp;   /* physmem installed */

char *boot_message;

char *netdev_path;

/*
 * Support new boot properties "boot-start" and "boot-end" for
 * Freeze/Thaw project.
 */
caddr_t start_addr, end_addr;

#define	BOOT_BADPROP	-1
#define	BOOT_SUCCESS	0
#define	BOOT_FAILURE	-1
#define	NIL		0

#define	strequal(p, q)	(strcmp((p), (q)) == 0)


/*
 * This routine is used by stand/lib/$PROC/libnfs.a in case it comes up with a
 * default filename, and by bootflags() if a default filename is specified in
 * the boot arguments.
 */
void
set_default_filename(char *filename)
{
	kernname = filename;
}


static const struct bplist {
	char	*name;
	void	*val;
	uint_t	size;
} bprop_tab[] = {
	"boot-args",		&v2args,		0,
	"boot-path",		&v2path,		0,
	"fstype",		&systype,		0,
	"whoami",		&my_own_name,		0,
	"mfg-name",		&mfg_name,		0,
	"impl-arch-name",	&impl_arch_name,	0,
	"module-path",		&module_path,		0,
	"virt-avail",		&vfreelistp,		0,
	"phys-avail",		&pfreelistp,		0,
	"phys-installed",	&pinstalledp,		0,
	"default-name",		&kernname,		0,
	"extent",		&memlistextent,		sizeof (memlistextent),
	"vac",			&vac,			sizeof (vac),
	"cache-on?",		&cache_state,		sizeof (int),
	"memory-update",	0,			0,
	"boot-start",		&start_addr,		sizeof (start_addr),
	"boot-end",		&scratchmemp,		sizeof (scratchmemp),
	"boot-message",		&boot_message,		0,
	"bootp-response",	&bootp_response,	0,
	"netdev-path",		&netdev_path,		0,
	0,			0,			0
};

/*
 *  These routines implement the boot getprop interface.
 *  They are designed to mimic the corresponding devr_{getprop,getproplen}
 *  functions.
 *  The assumptions is that the basic property is an unsigned int.  Other
 *  types (including lists) are special cases.
 */

/*ARGSUSED*/
int
bgetproplen(struct bootops *bop, char *name)
{
	int size = 0;
	struct bplist *p;
	struct memlist *ml;

	/* this prop has side effects only.  No length.  */
	if (strequal(name, "memory-update"))
		return (BOOT_SUCCESS);

	for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) {

		/* got a linked list?  */
		if ((strequal(name, "virt-avail") && strequal(name, p->name)) ||
		    (strequal(name, "phys-avail") && strequal(name, p->name)) ||
		    (strequal(name, "phys-installed") &&
		    strequal(name, p->name))) {

			for (ml = *((struct memlist **)p->val);
					ml != NIL;
					ml = ml->next)

				/*
				 *  subtract out the ptrs for our local
				 *  linked list.  The application will
				 *  only see an array.
				 */
				size += (int)(sizeof (struct memlist) -
						2*sizeof (struct memlist *));
			return (size);

		} else if (strequal(name, p->name)) {

			/* if we already know the size, return it */
			if (p->size != 0)
				return (p->size);
			else {
				if (*((char **)p->val) == NIL)
					return (0);	/* NULL is allowed */

				/* don't forget the null termination */
				return (strlen(*((char **)p->val)) + 1);
			}
		}
	}
	return (BOOT_BADPROP);
}

/*ARGSUSED*/
int
bgetprop(struct bootops *bop, char *name, void *buf)
{
	struct bplist *p;
	struct memlist *ml;

	if (strequal(name, "memory-update")) {
/*
 *		dprintf("bgetprop:  updating memlists.\n");
 */
		update_memlist("virtual-memory", "available", &vfreelistp);
		update_memlist("memory", "available", &pfreelistp);
		return (BOOT_SUCCESS);
	}

	if (strequal(name, "boot-start")) {
		start_addr = (caddr_t)_start;
		bcopy((char *)(&start_addr), buf, sizeof (start_addr));
		return (BOOT_SUCCESS);
	}

	if (strequal(name, "boot-end")) {
		/*
		 * The true end of boot should be scratchmemp,
		 * boot gets its dynamic memory from the scratchmem
		 * which is the first 4M of the physical memory,
		 * and they are mapped 1:1.
		 */
		end_addr = scratchmemp;
		bcopy((char *)(&end_addr), buf, sizeof (scratchmemp));
		return (BOOT_SUCCESS);
	}

	for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) {

		/* gotta linked list? */
		if ((strequal(name, "virt-avail") && strequal(name, p->name)) ||
		    (strequal(name, "phys-avail") && strequal(name, p->name)) ||
		    (strequal(name, "phys-installed") &&
		    strequal(name, p->name))) {

			u_longlong_t *t = buf;

			for (ml = *((struct memlist **)p->val);
					ml != NIL;
					ml = ml->next) {

				/* copy out into an array */
				*t++ = ml->address;
				*t++ = ml->size;
			}
			return (BOOT_SUCCESS);
		} else if (strequal(name, p->name)) {
			if (p->size != 0) {
				bcopy(p->val, buf, p->size);
			} else {
				(void) strcpy((char *)buf, *((char **)p->val));
			}
			return (BOOT_SUCCESS);
		}
	}
	return (BOOT_FAILURE);
}

/*
 *  If the user wants the first property in the list, he passes in a
 *  null string.  The routine will always return a ptr to the name of the
 *  next prop, except when there are no more props.  In that case, it will
 *  return a null string.
 */

/*ARGSUSED*/
char *
bnextprop(struct bootops *bop, char *prev)
{
	struct bplist *p;

	/* user wants the firstprop */
	if (*prev == 0)
		return (bprop_tab->name);

	for (p = (struct bplist *)bprop_tab; p->name != (char *)0; p++) {

		if (strequal(prev, p->name))
			/*
			 * if prev is the last valid prop,
			 * we will return our terminator (0).
			 */
			return ((++p)->name);


	}
	return ((char *)0);
}