summaryrefslogtreecommitdiff
path: root/usr/src/uts/sparc/os/bootops.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/sparc/os/bootops.c')
-rw-r--r--usr/src/uts/sparc/os/bootops.c907
1 files changed, 377 insertions, 530 deletions
diff --git a/usr/src/uts/sparc/os/bootops.c b/usr/src/uts/sparc/os/bootops.c
index f01c0f8f65..b0231cae13 100644
--- a/usr/src/uts/sparc/os/bootops.c
+++ b/usr/src/uts/sparc/os/bootops.c
@@ -2,9 +2,8 @@
* 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.
+ * 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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -35,670 +34,518 @@
*/
#include <sys/types.h>
+#include <sys/systm.h>
#include <sys/reboot.h>
#include <sys/param.h>
#include <sys/varargs.h>
#include <sys/obpdefs.h>
-#include <sys/promif.h>
+#include <sys/promimpl.h>
+#include <sys/prom_plat.h>
#include <sys/bootconf.h>
#include <sys/bootstat.h>
+#include <sys/kobj_impl.h>
-/*
- * Implementation of the "version" boot service.
- * Return the compiled version number of this implementation.
- *
- * Note: An individual service can be tested for and versioned with
- * bop_serviceavail();
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] Res0: returned version number
- */
-uint_t
-bop_getversion(struct bootops *bop)
+struct bootops *bootops;
+struct bootops kbootops;
+
+pnode_t chosennode;
+
+#define FAKE_ROOT (pnode_t)1
+
+struct fakeprop {
+ char *bootname;
+ pnode_t promnode;
+ char *promname;
+} fakeprops[] = {
+ { "mfg-name", FAKE_ROOT, "name" },
+ { NULL, 0, NULL }
+};
+
+static void
+fakelook_init(void)
{
- return (bop->bsys_version);
+ struct fakeprop *fpp = fakeprops;
+
+ while (fpp->bootname != NULL) {
+ switch (fpp->promnode) {
+ case FAKE_ROOT:
+ fpp->promnode = prom_rootnode();
+ break;
+ }
+ fpp++;
+ }
+}
+
+static struct fakeprop *
+fakelook(const char *prop)
+{
+ struct fakeprop *fpp = fakeprops;
+
+ while (fpp->bootname != NULL) {
+ if (strcmp(prop, fpp->bootname) == 0)
+ return (fpp);
+ fpp++;
+ }
+ return (NULL);
}
+ihandle_t bfs_ih = OBP_BADNODE;
+ihandle_t afs_ih = OBP_BADNODE;
+
+void
+bop_init(void)
+{
+ chosennode = prom_chosennode();
+
+ fakelook_init();
+
+ /* fake bootops - it needs to point to non-NULL */
+ bootops = &kbootops;
+}
+
+#define MAXPROMFD 16
+
+static ihandle_t prom_ihs[MAXPROMFD];
+int filter_etc = 1;
/*
* Implementation of the "open" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] filename string
- * args[4] flags
- * args[5] Res0: returned result
- *
*/
+/*ARGSUSED*/
int
-bop_open(struct bootops *bop, char *name, int flags)
+bop_open(const char *name, int flags)
+{
+ int fd = -1, layered;
+ ihandle_t ih;
+
+ /*
+ * Only look underneath archive for /etc files
+ */
+ layered = filter_etc ?
+ strncmp(name, "/etc", sizeof ("/etc") - 1) == 0 : 1;
+
+ if (afs_ih != OBP_BADNODE) {
+ ih = afs_ih;
+ fd = prom_fopen(ih, (char *)name);
+ if (fd == -1 && !layered)
+ return (BOOT_SVC_FAIL);
+ }
+ if (fd == -1 && bfs_ih != OBP_BADNODE) {
+ ih = bfs_ih;
+ fd = prom_fopen(ih, (char *)name);
+ }
+ if (fd == -1)
+ return (BOOT_SVC_FAIL);
+ ASSERT(fd < MAXPROMFD);
+ ASSERT(prom_ihs[fd] == 0);
+ prom_ihs[fd] = ih;
+ return (fd);
+}
+
+static void
+spinner(void)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("open");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(name);
- args[4] = boot_int2cell(flags);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[5]));
+ static int pos;
+ static char ind[] = "|/-\\"; /* that's entertainment? */
+ static int blks_read;
+
+ if ((blks_read++ & 0x3) == 0)
+ prom_printf("%c\b", ind[pos++ & 3]);
}
/*
* Implementation of the "read" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] boot-opened file descriptor
- * args[4] client's buffer
- * args[5] size of read request
- * args[6] Res0: returned result
- *
*/
int
-bop_read(struct bootops *bop, int fd, caddr_t buf, size_t size)
+bop_read(int fd, caddr_t buf, size_t size)
{
- boot_cell_t args[7];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("read");
- args[1] = 3;
- args[2] = 1;
-
- args[3] = boot_int2cell(fd);
- args[4] = boot_ptr2cell(buf);
- args[5] = boot_uint2cell(size);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[6]));
+ ASSERT(prom_ihs[fd] != 0);
+ spinner();
+ return (prom_fread(prom_ihs[fd], fd, buf, size));
}
/*
* Implementation of the "seek" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] boot-opened file descriptor
- * args[4] offset hi XXX just use one cell for offset?
- * args[5] offset lo
- * args[6] Res0: returned result
*/
int
-bop_seek(struct bootops *bop, int fd, off_t hi, off_t lo)
+bop_seek(int fd, off_t off)
{
- boot_cell_t args[7];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("seek");
- args[1] = 3;
- args[2] = 1;
-
- args[3] = boot_int2cell(fd);
- args[4] = boot_offt2cell(hi);
- args[5] = boot_offt2cell(lo);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[6]));
+ ASSERT(prom_ihs[fd] != 0);
+ return (prom_fseek(prom_ihs[fd], fd, off));
}
/*
* Implementation of the "close" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] boot-opened file descriptor
- * args[4] Res0: returned result
*/
int
-bop_close(struct bootops *bop, int fd)
+bop_close(int fd)
{
- boot_cell_t args[5];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("close");
- args[1] = 1;
- args[2] = 1;
-
- args[3] = boot_int2cell(fd);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[4]));
+ ASSERT(prom_ihs[fd] != 0);
+ prom_fclose(prom_ihs[fd], fd);
+ prom_ihs[fd] = 0;
+ return (0);
}
/*
- * Implementation of the "alloc" boot service.
+ * Simple temp memory allocator
*
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] virtual hint
- * args[4] size to allocate
- * args[5] alignment
- * args[6] Res0: returned result
+ * >PAGESIZE allocations are gotten directly from prom at bighand
+ * smaller ones are satisfied from littlehand, which does a
+ * 1 page bighand allocation when it runs out of memory
*/
-caddr_t
-bop_alloc(struct bootops *bop, caddr_t virthint, size_t size, int align)
-{
- boot_cell_t args[7];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("alloc");
- args[1] = 3;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(virthint);
- args[4] = boot_size2cell(size);
- args[5] = boot_int2cell(align);
- (void) (bsys_1275_call)(args);
- return ((caddr_t)(uintptr_t)boot_ptr2cell((uintptr_t)args[6]));
-}
+static caddr_t bighand = (caddr_t)BOOTTMPBASE;
+static caddr_t littlehand = (caddr_t)BOOTTMPBASE;
+
+#define NTMPALLOC 128
+
+static caddr_t temp_base[NTMPALLOC];
+static size_t temp_size[NTMPALLOC];
+static int temp_indx;
+
+#if defined(C_OBP)
+void cobp_free_mem(caddr_t, size_t);
+#endif /* C_OBP */
+
/*
- * Implementation of the "alloc_virt" boot service
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] virtual address
- * args[4] size to allocate
- * args[5] Resi: returned result
+ * temporary memory storage until bop_tmp_freeall is called
+ * (after the kernel heap is initialized)
*/
caddr_t
-bop_alloc_virt(struct bootops *bop, caddr_t virt, size_t size)
+bop_temp_alloc(size_t size, int align)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("alloc_virt");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(virt);
- args[4] = boot_size2cell(size);
- (void) (bsys_1275_call)(args);
- return ((caddr_t)(uintptr_t)boot_ptr2cell((uintptr_t)args[5]));
+ caddr_t ret;
+
+ /*
+ * OBP allocs 10MB to boot, which is where virthint = 0
+ * memory was allocated from. Without boot, we allocate
+ * from BOOTTMPBASE and free when we're ready to take
+ * the machine from OBP
+ */
+ if (size < PAGESIZE) {
+ size_t left =
+ ALIGN(littlehand, PAGESIZE) - (uintptr_t)littlehand;
+
+ size = roundup(size, MAX(align, 8));
+ if (size <= left) {
+ ret = littlehand;
+ littlehand += size;
+ return (ret);
+ }
+ littlehand = bighand + size;
+ }
+ size = roundup(size, PAGESIZE);
+ ret = prom_alloc(bighand, size, align);
+ if (ret == NULL)
+ prom_panic("boot temp overflow");
+ bighand += size;
+
+ /* log it for bop_fini() */
+ temp_base[temp_indx] = ret;
+ temp_size[temp_indx] = size;
+ if (++temp_indx == NTMPALLOC)
+ prom_panic("out of bop temp space");
+
+ return (ret);
}
-/*
- * Implementation of the "free" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] virtual hint
- * args[4] size to free
- * args[5] Res0: returned result
- */
-/*ARGSUSED*/
void
-bop_free(struct bootops *bop, caddr_t virt, size_t size)
+bop_temp_freeall(void)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("free");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(virt);
- args[4] = boot_size2cell(size);
- (void) (bsys_1275_call)(args);
+ int i;
+
+ /*
+ * We have to call prom_free() with the same args
+ * as we used in prom_alloc()
+ */
+ for (i = 0; i < NTMPALLOC; i++) {
+ if (temp_base[i] == NULL)
+ break;
+#if !defined(C_OBP)
+ prom_free(temp_base[i], temp_size[i]);
+#else /* !C_OBP */
+ cobp_free_mem(temp_base[i], temp_size[i]);
+#endif /* !C_OBP */
+ }
}
+
/*
- * Implementation of the "map" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] virtual address
- * args[4] space of phys addr
- * args[5] phys addr
- * args[6] size
- * args[7] Res0: returned result
+ * Implementation of the "alloc" boot service.
*/
-/*ARGSUSED*/
caddr_t
-bop_map(struct bootops *bop, caddr_t virt, int space,
- caddr_t phys, size_t size)
+bop_alloc(caddr_t virthint, size_t size, int align)
{
- boot_cell_t args[8];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("map");
- args[1] = 3;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(virt);
- args[4] = boot_int2cell(space);
- args[5] = boot_ptr2cell(phys);
- args[6] = boot_size2cell(size);
- (void) (bsys_1275_call)(args);
- return ((caddr_t)boot_cell2ptr(args[7]));
+ if (virthint == NULL)
+ return (bop_temp_alloc(size, align));
+ return (prom_alloc(virthint, size, align));
}
/*
- * Implementation of the "unmap" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] virtual address
- * args[4] size of chunk
- * args[5] Res0: returned result
+ * Implementation of the "alloc_virt" boot service
*/
-/*ARGSUSED*/
-void
-bop_unmap(struct bootops *bop, caddr_t virt, size_t size)
+caddr_t
+bop_alloc_virt(caddr_t virt, size_t size)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("unmap");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(virt);
- args[4] = boot_size2cell(size);
- (void) (bsys_1275_call)(args);
+ return (prom_claim_virt(size, virt));
}
/*
- * Implementation of the "quiesce" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] Res0: returned result
+ * Implementation of the "free" boot service.
*/
/*ARGSUSED*/
void
-bop_quiesce_io(struct bootops *bop)
+bop_free(caddr_t virt, size_t size)
{
- boot_cell_t args[4];
- int (*bsys_1275_call)(void *);
+ prom_free(virt, size);
+}
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("quiesce");
- args[1] = 0;
- args[2] = 1;
- (void) (bsys_1275_call)(args);
-}
/*
* Implementation of the "getproplen" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] property name string
- * args[4] Res0: returned result
*/
/*ARGSUSED*/
int
-bop_getproplen(struct bootops *bop, char *name)
+bop_getproplen(const char *name)
{
- boot_cell_t args[7];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("getproplen");
- args[1] = 1;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(name);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[4]));
+ struct fakeprop *fpp;
+ pnode_t node;
+ char *prop;
+
+ fpp = fakelook(name);
+ if (fpp != NULL) {
+ node = fpp->promnode;
+ prop = fpp->promname;
+ } else {
+ node = chosennode;
+ prop = (char *)name;
+ }
+ return (prom_getproplen(node, prop));
}
/*
* Implementation of the "getprop" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] property name string
- * args[4] buffer pointer to hold value of the property
- * args[5] Res0: returned result
*/
/*ARGSUSED*/
int
-bop_getprop(struct bootops *bop, char *name, void *value)
+bop_getprop(const char *name, void *value)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("getprop");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(name);
- args[4] = boot_ptr2cell(value);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[5]));
+ struct fakeprop *fpp;
+ pnode_t node;
+ char *prop;
+
+ fpp = fakelook(name);
+ if (fpp != NULL) {
+ node = fpp->promnode;
+ prop = fpp->promname;
+ } else {
+ node = chosennode;
+ prop = (char *)name;
+ }
+ return (prom_getprop(node, prop, value));
}
/*
- * Implementation of the "nextprop" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] previous property name string
- * args[4] Res0: returned result
+ * Implementation of the "print" boot service.
*/
/*ARGSUSED*/
-char *
-bop_nextprop(struct bootops *bop, char *prevprop)
+void
+bop_printf(void *ops, const char *fmt, ...)
{
- boot_cell_t args[5];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("nextprop");
- args[1] = 1;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(prevprop);
- (void) (bsys_1275_call)(args);
- return ((char *)boot_cell2ptr(args[4]));
+ va_list adx;
+
+ va_start(adx, fmt);
+ prom_vprintf(fmt, adx);
+ va_end(adx);
}
/*
- * Implementation of the "puts" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] string to print
+ * Special routine for kmdb
*/
-/*ARGSUSED*/
void
-bop_puts(struct bootops *bop, char *string)
+bop_putsarg(const char *fmt, char *arg)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
- void (*bsys_printf)(struct bootops *, char *, ...);
-
- /* so new kernel, old boot can print a message before dying */
- if (!BOOTOPS_ARE_1275(bop)) {
- /* use uintptr_t to suppress the gcc warning */
- bsys_printf = (void (*)(struct bootops *, char *, ...))
- (uintptr_t)bop->bsys_printf;
- (*bsys_printf)(bop, string);
- return;
- }
-
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("puts");
- args[1] = 1;
- args[2] = 0;
-
- args[3] = boot_ptr2cell(string);
- (void) (bsys_1275_call)(args);
-
+ prom_printf(fmt, arg);
}
/*
- * Implementation of the "putsarg" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] string to print (with '%*' format)
- * args[4] 64-bit thing to print
+ * panic for krtld only
*/
-/*ARGSUSED*/
void
-bop_putsarg(struct bootops *bop, const char *string, ...)
+bop_panic(const char *s)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
- void (*bsys_printf)(struct bootops *, char *, ...);
- va_list ap;
- const char *fmt = string;
- int ells = 0;
- uint64_t arg;
-
- /*
- * We need to do the minimum printf-like stuff here to figure
- * out the size of argument, if present.
- */
- while (*fmt) {
- if (*fmt++ != '%')
- continue;
- if (*fmt == '%') {
- fmt++;
- continue;
- }
-
- while (*fmt >= '0' && *fmt <= '9')
- fmt++;
- for (ells = 0; *fmt == 'l'; fmt++)
- ells++;
- va_start(ap, string);
- switch (*fmt) {
- case 's':
- /* use uintptr_t to suppress the gcc warning */
- arg = (uint64_t)(uintptr_t)va_arg(ap, char *);
- break;
- case 'p':
- arg = (uint64_t)(uintptr_t)va_arg(ap, void *);
- break;
- case 'd':
- case 'D':
- case 'x':
- case 'X':
- case 'u':
- case 'U':
- case 'o':
- case 'O':
- if (ells == 0)
- arg = (uint64_t)va_arg(ap, uint_t);
- else if (ells == 1)
- arg = (uint64_t)va_arg(ap, ulong_t);
- else
- arg = (uint64_t)va_arg(ap, uint64_t);
- break;
- default:
- arg = (uint64_t)va_arg(ap, uint_t);
- break;
- }
- va_end(ap);
- break;
- }
-
- /* so new kernel, old boot can print a message before dying */
- if (!BOOTOPS_ARE_1275(bop)) {
- /* use uintptr_t to suppress the gcc warning */
- bsys_printf = (void (*)(struct bootops *, char *, ...))
- (uintptr_t)bop->bsys_printf;
- (*bsys_printf)(bop, (char *)string, arg);
- return;
- }
-
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("putsarg");
- args[1] = 2;
- args[2] = 0;
- args[3] = boot_ptr2cell(string);
- args[4] = boot_uint642cell(arg);
-
- (void) (bsys_1275_call)(args);
+ prom_panic((char *)s);
}
/*
* Implementation of the "mount" boot service.
*
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] pathname string
- * args[4] Res0: returned result
*/
/*ARGSUSED*/
int
-bop_mountroot(struct bootops *bop, char *path)
+bop_mountroot(void)
{
- boot_cell_t args[5];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("mountroot");
- args[1] = 2;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(path);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[4]));
+ (void) prom_getprop(chosennode, "bootfs", (caddr_t)&bfs_ih);
+ (void) prom_getprop(chosennode, "archfs", (caddr_t)&afs_ih);
+ return ((bfs_ih == -1 && afs_ih == -1) ? BOOT_SVC_FAIL : BOOT_SVC_OK);
}
/*
* Implementation of the "unmountroot" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] Res0: returned result
*/
/*ARGSUSED*/
int
-bop_unmountroot(struct bootops *bop)
+bop_unmountroot(void)
{
- boot_cell_t args[4];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("unmountroot");
- args[1] = 0;
- args[2] = 1;
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[3]));
+ if (bfs_ih != OBP_BADNODE) {
+ (void) prom_close(bfs_ih);
+ bfs_ih = OBP_BADNODE;
+ }
+ if (afs_ih != OBP_BADNODE) {
+ (void) prom_close(afs_ih);
+ afs_ih = OBP_BADNODE;
+ }
+ return (BOOT_SVC_OK);
}
/*
- * Implementation of the "serviceavail" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] name string of service to be tested for
- * args[4] Res0: returned version number or 0
+ * Implementation of the "fstat" boot service.
*/
-/*ARGSUSED*/
int
-bop_serviceavail(struct bootops *bop, char *name)
+bop_fstat(int fd, struct bootstat *st)
{
- /* use uintptr_t to suppress the gcc warning */
- boot_cell_t args[5];
- int (*bsys_1275_call)(void *) =
- (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
-
- args[0] = boot_ptr2cell("serviceavail");
- args[1] = 1;
- args[2] = 1;
-
- args[3] = boot_ptr2cell(name);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[4]));
+ ASSERT(prom_ihs[fd] != 0);
+ return (prom_fsize(prom_ihs[fd], fd, (size_t *)&st->st_size));
}
+int
+boot_compinfo(int fd, struct compinfo *cb)
+{
+ ASSERT(prom_ihs[fd] != 0);
+ return (prom_compinfo(prom_ihs[fd], fd,
+ &cb->iscmp, &cb->fsize, &cb->blksize));
+}
+
+void
+bop_free_archive(void)
+{
+ char archive[OBP_MAXPATHLEN];
+ pnode_t arph;
+ uint32_t arbase, arsize, alloc_size;
+
+ /*
+ * If the ramdisk will eventually be root, or we weren't
+ * booted via the archive, then nothing to do here
+ */
+ if (root_is_ramdisk == B_TRUE ||
+ prom_getprop(chosennode, "bootarchive", archive) == -1)
+ return;
+ arph = prom_finddevice(archive);
+ if (arph == -1 ||
+ prom_getprop(arph, OBP_ALLOCSIZE, (caddr_t)&alloc_size) == -1 ||
+ prom_getprop(arph, OBP_SIZE, (caddr_t)&arsize) == -1 ||
+ prom_getprop(arph, OBP_ADDRESS, (caddr_t)&arbase) == -1)
+ prom_panic("can't free boot archive");
+
+#if !defined(C_OBP)
+ if (alloc_size == 0)
+ prom_free((caddr_t)(uintptr_t)arbase, arsize);
+ else {
+ uint32_t arend = arbase + arsize;
+
+ while (arbase < arend) {
+ prom_free((caddr_t)(uintptr_t)arbase,
+ MIN(alloc_size, arend - arbase));
+ arbase += alloc_size;
+ }
+ }
+#else /* !C_OBP */
+ cobp_free_mem((caddr_t)(uintptr_t)arbase, arsize);
+#endif /* !C_OBP */
+}
+
+#if defined(C_OBP)
/*
- * Implementation of the "fstat" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells
- * args[2] #result cells
- * args[3] fd
- * args[4] client's stat structure
+ * Blech. The C proms have a bug when freeing areas that cross
+ * page sizes, so we have to break up the free into sections
+ * bounded by the various pagesizes.
*/
-int
-bop_fstat(struct bootops *bop, int fd, struct bootstat *st)
+void
+cobp_free_mem(caddr_t base, size_t size)
{
- boot_cell_t args[6];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("fstat");
- args[1] = 2;
- args[2] = 1;
- args[3] = boot_int2cell(fd);
- args[4] = boot_ptr2cell(st);
- (void) (bsys_1275_call)(args);
- return (boot_cell2int(args[5]));
+ int i;
+ size_t len, pgsz;
+
+ /*
+ * Large pages only used when size > 512k
+ */
+ if (size < MMU_PAGESIZE512K ||
+ ((uintptr_t)base & MMU_PAGEOFFSET512K) != 0) {
+ prom_free(base, size);
+ return;
+ }
+ for (i = 3; i >= 0; i--) {
+ pgsz = page_get_pagesize(i);
+ if (size < pgsz)
+ continue;
+ len = size & ~(pgsz - 1);
+ prom_free(base, len);
+ base += len;
+ size -= len;
+ }
}
+#endif /* C_OBP */
+
/*
* Implementation of the "enter_mon" boot service.
- *
- * Calling spec:
- * args[0] Service name string
- * args[1] #argument cells (0)
- * args[2] #result cells (0)
*/
void
-bop_enter_mon(struct bootops *bop)
+bop_enter_mon(void)
+{
+ prom_enter_mon();
+}
+
+/*
+ * free elf info allocated by booter
+ */
+void
+bop_free_elf(void)
+{
+ uint32_t eadr;
+ uint32_t esize;
+ extern Addr dynseg;
+ extern size_t dynsize;
+
+ if (bop_getprop("elfheader-address", (caddr_t)&eadr) == -1 ||
+ bop_getprop("elfheader-length", (caddr_t)&esize) == -1)
+ prom_panic("missing elfheader");
+ prom_free((caddr_t)(uintptr_t)eadr, roundup(esize, PAGESIZE));
+
+ prom_free((caddr_t)(uintptr_t)dynseg, roundup(dynsize, PAGESIZE));
+}
+
+
+/* Simple message to indicate that the bootops pointer has been zeroed */
+#ifdef DEBUG
+int bootops_gone_on = 0;
+#define BOOTOPS_GONE() \
+ if (bootops_gone_on) \
+ prom_printf("The bootops vec is zeroed now!\n");
+#else
+#define BOOTOPS_GONE()
+#endif /* DEBUG */
+
+void
+bop_fini(void)
{
- boot_cell_t args[4];
- int (*bsys_1275_call)(void *);
-
- /* use uintptr_t to suppress the gcc warning */
- bsys_1275_call = (int (*)(void *))(uintptr_t)bop->bsys_1275_call;
- args[0] = boot_ptr2cell("enter_mon");
- args[1] = 0;
- args[2] = 0;
- (void) (bsys_1275_call)(args);
+ bop_free_archive();
+ (void) bop_unmountroot();
+ bop_free_elf();
+ bop_temp_freeall();
+
+ bootops = (struct bootops *)NULL;
+ BOOTOPS_GONE();
}