/*
* 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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <kmdb/kmdb_kctl.h>
#include <kmdb/kmdb_kdi.h>
#include <kmdb/kmdb_auxv.h>
#include <mdb/mdb_errno.h>
#include <sys/sysmacros.h>
#include <sys/bootconf.h>
#include <sys/kobj_impl.h>
#include <sys/promimpl.h>
#include <sys/kdi_impl.h>
#include <vm/seg_kmem.h>
#if defined(_LP64)
#else
#endif
/*
* kmdb will call its own copies of the promif routines during
* initialization. As these routines are intended to be used when the
* world is stopped, they don't attempt to grab the PROM lock. Very
* Bad Things could happen if kmdb called a prom routine while someone
* else was calling the kernel's copy of another prom routine, so we
* grab the PROM lock ourselves before we start initialization.
*/
#ifdef __sparc
#else
#define KCTL_PROM_LOCK
#define KCTL_PROM_UNLOCK
#endif
static int
kctl_init(void)
{
return (-1);
}
return (0);
}
static void
kctl_fini(void)
{
}
static uint_t
{
/* forward progess only, please */
}
return (ostate);
}
static int
{
/*
* The Intel boot memory allocator will cleverly map us onto a 4M
* page if we request the whole 4M Intel segment at once. This
* will break physical memory r/w, so we break the request into
* chunks. The allocator isn't smart enough to combine requests,
* so it'll give us a bunch of 4k pages.
*/
return (-1);
}
return (0);
}
static int
{
/* make sure there isn't something there already (like kadb) */
return (EAGAIN);
return (ENOMEM);
return (0);
}
static void
{
}
static void
kctl_memavail(void)
{
/*
* We're now free to allocate the non-fixed portion of the debugger's
* memory region.
*/
if (needed == 0)
return;
/*
* If we're going to wedge the machine during debugger startup,
* at least let them know why it's going to wedge.
*/
}
}
void
kctl_cleanup(void)
{
switch (state) {
case KCTL_ST_ACTIVE:
/* XXX there's a race here */
/*FALLTHROUGH*/
case KCTL_ST_DBG_ACTIVATED:
/*FALLTHROUGH*/
case KCTL_ST_THREAD_STARTED:
}
/*FALLTHROUGH*/
case KCTL_ST_MOD_NOTIFIERS:
/*FALLTHROUGH*/
/*FALLTHROUGH*/
case KCTL_ST_INITIALIZED:
/* There's no kmdb_fini */
case KCTL_ST_DSEG_ALLOCED:
/*FALLTHROUGH*/
}
}
static void
kctl_startup_modules(void)
{
/*
* Normal module load and unload is now available. Prior to this point,
* we could only load modules, and that only when the debugger was being
* initialized.
*
* We'll need to prepare the modules we've already loaded (if any) for
* the brave new world in which boot is unmapped.
*/
/*
* Process any outstanding loads or unloads and prepare for automatic
* module loading and unloading.
*/
(void) kctl_wr_process();
(void) kctl_set_state(KCTL_ST_MOD_NOTIFIERS);
do {
}
static void
kctl_startup_thread(void)
{
/*
* Create the worker thread, which will handle future requests from the
* debugger.
*/
(void) kctl_set_state(KCTL_ST_THREAD_STARTED);
}
static int
kctl_startup_boot(void)
{
int rc;
if (kctl_wr_process() < 0) {
kctl_warn("kmdb: failed to load modules");
return (-1);
}
kctl_warn("kmdb: failed to decompress CTF data "
ctf_errmsg(rc));
}
}
}
return (0);
}
static int
{
int rc;
if (rc < 0)
return (EMDB_KNOLOAD);
(void) kctl_set_state(KCTL_ST_INITIALIZED);
if (kctl_preactivate_isadep() != 0)
return (EIO);
(void) kctl_set_state(KCTL_ST_KCTL_PREACTIVATED);
return (0);
}
static int
{
(void) kctl_set_state(KCTL_ST_DBG_ACTIVATED);
/*
* fill in a few remaining debugvec entries.
*/
(void) kctl_set_state(KCTL_ST_ACTIVE);
return (0);
}
static int
{
return (0);
if (state == KCTL_ST_INACTIVE)
return (EMDB_KINACTIVE);
return (EMDB_KACTIVATING);
return (EMDB_KACTIVE);
return (EMDB_KDEACTIVATING);
else
return (EINVAL);
}
int
kctl_deactivate(void)
{
int rc;
if (kctl.kctl_boot_loaded) {
rc = EMDB_KNOUNLOAD;
goto deactivate_done;
}
goto deactivate_done;
/*
* The debugger will pass the request to the work thread, which will
* stop itself.
*/
return (rc);
}
/*
* Called from krtld, this indicates that the user loaded kmdb at boot. We
* track activation states, but we don't attempt to clean up if activation
* fails, because boot debugger load failures are fatal.
*
* Further complicating matters, various kernel routines, such as bcopy and
* mutex_enter, assume the presence of some basic state. On SPARC, it's the
* presence of a valid curthread pointer. On AMD64, it's a valid curcpu
* pointer in GSBASE. We set up temporary versions of these before beginning
* activation, and tear them down when we're done.
*/
int
const char **argv)
{
void *old;
#ifdef __lint
{
/*
* krtld does a name-based symbol lookup to find this routine. It then
* casts the address it gets, calling the result. We want to make sure
* that the call in krtld stays in sync with the prototype for this
* function, so we define a type (kctl_boot_activate_f) that matches the
* current prototype. The following assignment ensures that the type
* still matches the declaration, with lint as the enforcer.
*/
return (0);
}
#endif
if (kctl_init() < 0)
return (-1);
kctl_dprintf("beginning kmdb initialization");
if (memsz == 0)
kctl_warn("kmdb: failed to allocate %lu-byte debugger area at "
return (-1);
}
(void) kctl_set_state(KCTL_ST_DSEG_ALLOCED);
kctl_warn("kmdb: failed to activate");
return (-1);
}
if (kctl_startup_boot() < 0)
return (-1);
kctl_dprintf("finished with kmdb initialization");
return (0);
}
int
{
int rc;
rc = 0;
}
return (rc);
}
if (memsz == 0)
goto activate_fail;
(void) kctl_set_state(KCTL_ST_DSEG_ALLOCED);
goto activate_fail;
if ((rc = kctl_startup_activate(0)) != 0)
goto activate_fail;
kctl_memavail(); /* Must be after kdi_dvec is set */
return (0);
kctl_cleanup();
return (rc);
}
/*
* of two things will have happened:
*
* 1. The debugger was loaded at boot. We've progressed far enough into boot
* interface is the signal to the debugger that it can start allowing things
* like dmod loading and automatic CTF decompression - things which require
* the system services that have now been started.
*
* so we need to initialize. Activation will occur separately, so we don't
* have to worry about that.
*/
int
{
return (0);
}
int
kctl_detach(void)
{
}
};
(void *)&modlmisc,
};
/*
* Invoked only when debugger is loaded via modload - not invoked when debugger
* is loaded at boot. kctl_boot_activate needs to call anything (aside from
* mod_install) this function does.
*/
int
_init(void)
{
if (kctl_init() < 0)
return (EINVAL);
return (mod_install(&modlinkage));
}
int
{
}
int
_fini(void)
{
kctl_fini();
return (mod_remove(&modlinkage));
}