summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorMike Gerdts <mike.gerdts@joyent.com>2018-03-30 19:48:41 +0000
committerMike Gerdts <mike.gerdts@joyent.com>2018-04-03 17:44:20 +0000
commit7ab3f5348d729755d5a5fe1c679174b62ec4861e (patch)
treec71c4fc66370f8289ecbfdb40099dfa6e77d214d /usr/src
parent8098ab85dc79c5d039404142c4182f341a23ac0c (diff)
downloadillumos-joyent-7ab3f5348d729755d5a5fe1c679174b62ec4861e.tar.gz
OS-6858 vmm tracing framework is dead code
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Approved by: Patrick Mooney <patrick.mooney@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/intel/amd64/Makefile4
-rw-r--r--usr/src/cmd/mdb/intel/amd64/vmm/Makefile21
-rw-r--r--usr/src/cmd/mdb/intel/amd64/vmm/amd64/Makefile35
-rw-r--r--usr/src/cmd/mdb/intel/amd64/vmm/vmm.c237
-rw-r--r--usr/src/pkg/manifests/system-bhyve.mf7
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm.c2
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c175
-rw-r--r--usr/src/uts/i86pc/sys/vmm_dev.h5
-rw-r--r--usr/src/uts/i86pc/sys/vmm_impl.h33
9 files changed, 2 insertions, 517 deletions
diff --git a/usr/src/cmd/mdb/intel/amd64/Makefile b/usr/src/cmd/mdb/intel/amd64/Makefile
index 7749b75f37..f7bc890fb5 100644
--- a/usr/src/cmd/mdb/intel/amd64/Makefile
+++ b/usr/src/cmd/mdb/intel/amd64/Makefile
@@ -21,12 +21,12 @@
#
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright 2017 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
#
include ../../Makefile.common
-MODULES = $(COMMON_MODULES_PROC) $(COMMON_MODULES_KVM) uhci vmm
+MODULES = $(COMMON_MODULES_PROC) $(COMMON_MODULES_KVM) uhci
SUBDIRS = mdb mdb_ks kmdb libstandctf libstand .WAIT $(MODULES)
diff --git a/usr/src/cmd/mdb/intel/amd64/vmm/Makefile b/usr/src/cmd/mdb/intel/amd64/vmm/Makefile
deleted file mode 100644
index 0f2b977dfd..0000000000
--- a/usr/src/cmd/mdb/intel/amd64/vmm/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# This file and its contents are supplied under the terms of the
-# Common Development and Distribution License ("CDDL"), version 1.0.
-# You may only use this file in accordance with the terms of version
-# 1.0 of the CDDL.
-#
-# A full copy of the text of the CDDL should have accompanied this
-# source. A copy of the CDDL is also available via the Internet at
-# http://www.illumos.org/license/CDDL.
-#
-
-#
-# Copyright 2014 Pluribus Networks Inc.
-# Copyright 2017 Joyent, Inc.
-#
-
-#MAKEVARS = CW_NO_SHADOW=true __GNUC=
-
-include $(SRC)/Makefile.master
-$(BUILD64)SUBDIRS += $(MACH64)
-include ../../../Makefile.subdirs
diff --git a/usr/src/cmd/mdb/intel/amd64/vmm/amd64/Makefile b/usr/src/cmd/mdb/intel/amd64/vmm/amd64/Makefile
deleted file mode 100644
index e61be22d2a..0000000000
--- a/usr/src/cmd/mdb/intel/amd64/vmm/amd64/Makefile
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# This file and its contents are supplied under the terms of the
-# Common Development and Distribution License ("CDDL"), version 1.0.
-# You may only use this file in accordance with the terms of version
-# 1.0 of the CDDL.
-#
-# A full copy of the text of the CDDL should have accompanied this
-# source. A copy of the CDDL is also available via the Internet at
-# http://www.illumos.org/license/CDDL.
-#
-
-#
-# Copyright 2013 Pluribus Networks Inc.
-#
-
-MODULE = vmm.so
-MDBTGT = kvm
-
-MODSRCS = vmm.c
-
-include ../../../../../Makefile.cmd
-include ../../../../../Makefile.cmd.64
-include ../../../Makefile.amd64
-include ../../../../Makefile.module
-
-CPPFLAGS = -D_KERNEL -D_MACHDEP
-CPPFLAGS += -I$(COMPAT)/freebsd -I$(COMPAT)/freebsd/amd64
-CPPFLAGS += -I$(CONTRIB)/freebsd -I$(CONTRIB)/freebsd/amd64
-CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/uts/i86pc
-CPPFLAGS += -I$(SRC)/cmd/mdb/common
-
-#CPPFLAGS += -_cc=-xdryrun
-
-LINTTAGS += -erroff=E_FUNC_ARG_UNUSED
-LINTTAGS += -erroff=E_STATIC_UNUSED
diff --git a/usr/src/cmd/mdb/intel/amd64/vmm/vmm.c b/usr/src/cmd/mdb/intel/amd64/vmm/vmm.c
deleted file mode 100644
index 74c4ebc6c0..0000000000
--- a/usr/src/cmd/mdb/intel/amd64/vmm/vmm.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * This file and its contents are supplied under the terms of the
- * Common Development and Distribution License ("CDDL"), version 1.0.
- * You may only use this file in accordance with the terms of version
- * 1.0 of the CDDL.
- *
- * A full copy of the text of the CDDL should have accompanied this
- * source. A copy of the CDDL is also available via the Internet at
- * http://www.illumos.org/license/CDDL.
- */
-
-/*
- * Copyright 2014 Pluribus Networks Inc.
- */
-
-#include <sys/param.h>
-
-#include <mdb/mdb_modapi.h>
-#include <sys/cpuvar.h>
-#include <sys/varargs.h>
-#include <sys/vmm.h>
-#include <sys/vmm_impl.h>
-
-/*
- * VMM trace debug walker/dcmd code
- */
-
-/*
- * Initialize the vmm_trace_dmsg_t walker by either using the given starting
- * address, or reading the value of the kernel's vmm_debug_rbuf pointer.
- * We also allocate a vmm_trace_dmsg_t for storage, and save this using the
- * walk_data pointer.
- */
-static int
-vmm_dmsg_walk_i(mdb_walk_state_t *wsp)
-{
- uintptr_t rbuf_addr;
- vmm_trace_rbuf_t rbuf;
-
- if (wsp->walk_addr == NULL) {
- if (mdb_readvar(&rbuf_addr, "vmm_debug_rbuf") == -1) {
- mdb_warn("failed to read 'vmm_debug_rbuf'");
- return (WALK_ERR);
- }
-
- if (mdb_vread(&rbuf, sizeof (vmm_trace_rbuf_t), rbuf_addr)
- == -1) {
- mdb_warn("failed to read vmm_trace_rbuf_t at %p",
- rbuf_addr);
- return (WALK_ERR);
- }
-
- wsp->walk_addr = (uintptr_t)(vmm_trace_dmsg_t *)rbuf.dmsgh;
- }
-
- /*
- * Save ptr to head of ring buffer to prevent looping.
- */
- wsp->walk_arg = (void *)wsp->walk_addr;
- wsp->walk_data = mdb_alloc(sizeof (vmm_trace_dmsg_t), UM_SLEEP);
- return (WALK_NEXT);
-}
-
-/*
- * At each step, read a vmm_trace_dmsg_t into our private storage, and then
- * invoke the callback function. We terminate when we reach a NULL next
- * pointer.
- */
-static int
-vmm_dmsg_walk_s(mdb_walk_state_t *wsp)
-{
- int status;
-
- if (wsp->walk_addr == NULL)
- return (WALK_DONE);
-
- if (mdb_vread(wsp->walk_data, sizeof (vmm_trace_dmsg_t),
- wsp->walk_addr) == -1) {
- mdb_warn("failed to read vmm_trace_dmsg_t at %p",
- wsp->walk_addr);
- return (WALK_ERR);
- }
-
- status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
- wsp->walk_cbdata);
-
- wsp->walk_addr =
- (uintptr_t)(((vmm_trace_dmsg_t *)wsp->walk_data)->next);
-
- /*
- * If we've looped then we're done.
- */
- if (wsp->walk_addr == (uintptr_t)wsp->walk_arg)
- wsp->walk_addr = NULL;
-
- return (status);
-}
-
-/*
- * The walker's fini function is invoked at the end of each walk. Since we
- * dynamically allocated a vmm_trace_dmsg_t in vmm_dmsg_walk_i, we must
- * free it now.
- */
-static void
-vmm_dmsg_walk_f(mdb_walk_state_t *wsp)
-{
- mdb_free(wsp->walk_data, sizeof (vmm_trace_dmsg_t));
-}
-
-/*
- * This routine is used by the vmm_dmsg_dump dcmd to dump content of
- * VMM trace ring buffer.
- */
-int
-vmm_dmsg_dump(vmm_trace_dmsg_t *addr, int print_pathname, uint_t *printed)
-{
- vmm_trace_dmsg_t dmsg, *dmsgh = addr;
- char merge[1024];
-
- while (addr != NULL) {
- if (mdb_vread(&dmsg, sizeof (dmsg), (uintptr_t)addr) !=
- sizeof (dmsg)) {
- mdb_warn("failed to read message pointer in kernel");
- return (DCMD_ERR);
- }
-
- (void) mdb_snprintf(merge, sizeof (merge),
- "[%Y:%03d:%03d:%03d] : %s",
- dmsg.timestamp.tv_sec,
- (int)dmsg.timestamp.tv_nsec/1000000,
- (int)(dmsg.timestamp.tv_nsec/1000)%1000,
- (int)dmsg.timestamp.tv_nsec%1000,
- dmsg.buf);
-
- mdb_printf("%s", merge);
-
- if (printed != NULL) {
- (*printed)++;
- }
-
- if (((addr = dmsg.next) == NULL) || (dmsg.next == dmsgh)) {
- break;
- }
- }
-
- return (DCMD_OK);
-}
-
-/*
- * 1. Process flag passed to vmm_dmsg_dump dcmd.
- * 2. Obtain VMM trace ring buffer pointer.
- * 3. Pass VMM trace ring buffer pointer to vmm_dmsg_dump()
- * to dump content of VMM trace ring buffer.
- */
-int
-vmm_rbuf_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
-{
- vmm_trace_rbuf_t rbuf;
- uint_t printed = 0; /* have we printed anything? */
- int print_pathname = FALSE;
- int rval = DCMD_OK;
-
- if (argc > 1) {
- return (DCMD_USAGE);
- }
-
- if (mdb_getopts(argc, argv,
- 'a', MDB_OPT_SETBITS, TRUE, &print_pathname) != argc) {
- return (DCMD_USAGE);
- }
-
- /*
- * If ring buffer address not provided try to obtain
- * it using vmm_debug_rbuf global.
- */
- if ((addr == NULL) || !(flags & DCMD_ADDRSPEC)) {
- if (mdb_readvar(&addr, "vmm_debug_rbuf") == -1) {
- mdb_warn("Failed to read 'vmm_debug_rbuf'.");
- return (DCMD_ERR);
- }
- }
-
- if (mdb_vread(&rbuf, sizeof (rbuf), addr) != sizeof (rbuf)) {
- mdb_warn("Failed to read ring buffer in kernel.");
- return (DCMD_ERR);
- }
-
- if (rbuf.dmsgh == NULL) {
- mdb_printf("The vmm trace ring buffer is empty.\n");
- return (DCMD_OK);
- }
-
- rval = vmm_dmsg_dump((vmm_trace_dmsg_t *)rbuf.dmsgh,
- print_pathname, &printed);
-
- if (rval != DCMD_OK) {
- return (rval);
- }
-
- if (printed == 0) {
- mdb_warn("Failed to read vmm trace ring buffer.");
- return (DCMD_ERR);
- }
-
- return (rval);
-}
-
-/*
- * MDB module linkage information:
- *
- * We declare a list of structures describing our dcmds, a list of structures
- * describing our walkers, and a function named _mdb_init to return a pointer
- * to our module information.
- */
-
-static const mdb_dcmd_t dcmds[] = {
- { "vmm_dmsg_dump", "[-a]", "Dump vmm trace debug messages",
- vmm_rbuf_dump },
- { NULL }
-};
-
-static const mdb_walker_t walkers[] = {
- { "vmm_dmsg",
- "walk ring buffer containing vmm trace debug messages",
- vmm_dmsg_walk_i, vmm_dmsg_walk_s, vmm_dmsg_walk_f },
- { NULL }
-};
-
-static const mdb_modinfo_t modinfo = {
- MDB_API_VERSION, dcmds, walkers
-};
-
-const mdb_modinfo_t *
-_mdb_init(void)
-{
- return (&modinfo);
-}
diff --git a/usr/src/pkg/manifests/system-bhyve.mf b/usr/src/pkg/manifests/system-bhyve.mf
index 9ddbd1cb5f..4b95d3986a 100644
--- a/usr/src/pkg/manifests/system-bhyve.mf
+++ b/usr/src/pkg/manifests/system-bhyve.mf
@@ -30,22 +30,16 @@ set name=info.classification \
value=org.opensolaris.category.2008:System/Virtualization
set name=variant.arch value=i386
dir path=kernel group=sys
-dir path=kernel/kmdb group=sys
-dir path=kernel/kmdb/$(ARCH64) group=sys
dir path=lib group=bin
dir path=lib/$(ARCH64) group=bin
dir path=usr group=sys
dir path=usr/kernel/drv group=sys
dir path=usr/kernel/drv/$(ARCH64) group=sys
dir path=usr/lib group=bin
-dir path=usr/lib/mdb group=sys
-dir path=usr/lib/mdb/kvm group=sys
-dir path=usr/lib/mdb/kvm/$(ARCH64) group=sys
dir path=usr/sbin
driver name=ppt
driver name=viona
driver name=vmm
-file path=kernel/kmdb/$(ARCH64)/vmm mode=0555
file path=lib/$(ARCH64)/libvmmapi.so.1
file path=usr/kernel/drv/$(ARCH64)/ppt
file path=usr/kernel/drv/$(ARCH64)/viona
@@ -53,7 +47,6 @@ file path=usr/kernel/drv/$(ARCH64)/vmm
file path=usr/kernel/drv/ppt.conf
file path=usr/kernel/drv/viona.conf
file path=usr/kernel/drv/vmm.conf
-file path=usr/lib/mdb/kvm/$(ARCH64)/vmm.so mode=0555
file path=usr/sbin/bhyve mode=0555
file path=usr/sbin/bhyvectl mode=0555
license lic_CDDL license=lic_CDDL
diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c
index 6332a094d4..2835857bf3 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm.c
@@ -459,7 +459,6 @@ vmm_mod_load()
{
int error;
- vmmdev_init();
error = vmm_init();
if (error == 0)
vmm_initialized = 1;
@@ -472,7 +471,6 @@ vmm_mod_unload()
{
int error;
- vmmdev_cleanup();
error = VMM_CLEANUP();
if (error)
return (error);
diff --git a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
index 7841735ef2..12c343e467 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm_sol_dev.c
@@ -77,18 +77,6 @@ static sdev_plugin_hdl_t vmm_sdev_hdl;
/* From uts/i86pc/io/vmm/intel/vmx.c */
extern int vmx_x86_supported(char **);
-/*
- * vmm trace ring
- */
-int vmm_dmsg_ring_size = VMM_DMSG_RING_SIZE;
-static vmm_trace_rbuf_t *vmm_debug_rbuf;
-static vmm_trace_dmsg_t *vmm_trace_dmsg_alloc(void);
-static void vmm_trace_dmsg_free(void);
-static void vmm_trace_rbuf_alloc(void);
-#if notyet
-static void vmm_trace_rbuf_free(void);
-#endif
-
/* Holds and hooks from drivers external to vmm */
struct vmm_hold {
list_node_t vmh_node;
@@ -99,169 +87,6 @@ struct vmm_hold {
static int vmm_drv_block_hook(vmm_softc_t *, boolean_t);
-/*
- * This routine is used to manage debug messages
- * on ring buffer.
- */
-static vmm_trace_dmsg_t *
-vmm_trace_dmsg_alloc(void)
-{
- vmm_trace_dmsg_t *dmsg_alloc, *dmsg = vmm_debug_rbuf->dmsgp;
-
- if (vmm_debug_rbuf->looped == TRUE) {
- vmm_debug_rbuf->dmsgp = dmsg->next;
- return (vmm_debug_rbuf->dmsgp);
- }
-
- /*
- * If we're looping for the first time,
- * connect the ring.
- */
- if (((vmm_debug_rbuf->size + (sizeof (vmm_trace_dmsg_t))) >
- vmm_debug_rbuf->maxsize) && (vmm_debug_rbuf->dmsgh != NULL)) {
- dmsg->next = vmm_debug_rbuf->dmsgh;
- vmm_debug_rbuf->dmsgp = vmm_debug_rbuf->dmsgh;
- vmm_debug_rbuf->looped = TRUE;
- return (vmm_debug_rbuf->dmsgp);
- }
-
- /* If we've gotten this far then memory allocation is needed */
- dmsg_alloc = kmem_zalloc(sizeof (vmm_trace_dmsg_t), KM_NOSLEEP);
- if (dmsg_alloc == NULL) {
- vmm_debug_rbuf->allocfailed++;
- return (dmsg_alloc);
- } else {
- vmm_debug_rbuf->size += sizeof (vmm_trace_dmsg_t);
- }
-
- if (vmm_debug_rbuf->dmsgp != NULL) {
- dmsg->next = dmsg_alloc;
- vmm_debug_rbuf->dmsgp = dmsg->next;
- return (vmm_debug_rbuf->dmsgp);
- } else {
- /*
- * We should only be here if we're initializing
- * the ring buffer.
- */
- if (vmm_debug_rbuf->dmsgh == NULL) {
- vmm_debug_rbuf->dmsgh = dmsg_alloc;
- } else {
- /* Something is wrong */
- kmem_free(dmsg_alloc, sizeof (vmm_trace_dmsg_t));
- return (NULL);
- }
-
- vmm_debug_rbuf->dmsgp = dmsg_alloc;
- return (vmm_debug_rbuf->dmsgp);
- }
-}
-
-/*
- * Free all messages on debug ring buffer.
- */
-static void
-vmm_trace_dmsg_free(void)
-{
- vmm_trace_dmsg_t *dmsg_next, *dmsg = vmm_debug_rbuf->dmsgh;
-
- while (dmsg != NULL) {
- dmsg_next = dmsg->next;
- kmem_free(dmsg, sizeof (vmm_trace_dmsg_t));
-
- /*
- * If we've looped around the ring than we're done.
- */
- if (dmsg_next == vmm_debug_rbuf->dmsgh) {
- break;
- } else {
- dmsg = dmsg_next;
- }
- }
-}
-
-static void
-vmm_trace_rbuf_alloc(void)
-{
- vmm_debug_rbuf = kmem_zalloc(sizeof (vmm_trace_rbuf_t), KM_SLEEP);
-
- mutex_init(&vmm_debug_rbuf->lock, NULL, MUTEX_DRIVER, NULL);
-
- if (vmm_dmsg_ring_size > 0) {
- vmm_debug_rbuf->maxsize = vmm_dmsg_ring_size;
- }
-}
-
-#if notyet
-static void
-vmm_trace_rbuf_free(void)
-{
- vmm_trace_dmsg_free();
- mutex_destroy(&vmm_debug_rbuf->lock);
- kmem_free(vmm_debug_rbuf, sizeof (vmm_trace_rbuf_t));
-}
-#endif
-
-static void
-vmm_vtrace_log(const char *fmt, va_list ap)
-{
- vmm_trace_dmsg_t *dmsg;
-
- if (vmm_debug_rbuf == NULL) {
- return;
- }
-
- /*
- * If max size of ring buffer is smaller than size
- * required for one debug message then just return
- * since we have no room for the debug message.
- */
- if (vmm_debug_rbuf->maxsize < (sizeof (vmm_trace_dmsg_t))) {
- return;
- }
-
- mutex_enter(&vmm_debug_rbuf->lock);
-
- /* alloc or reuse on ring buffer */
- dmsg = vmm_trace_dmsg_alloc();
-
- if (dmsg == NULL) {
- /* resource allocation failed */
- mutex_exit(&vmm_debug_rbuf->lock);
- return;
- }
-
- gethrestime(&dmsg->timestamp);
-
- (void) vsnprintf(dmsg->buf, sizeof (dmsg->buf), fmt, ap);
-
- mutex_exit(&vmm_debug_rbuf->lock);
-}
-
-void
-vmm_trace_log(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vmm_vtrace_log(fmt, ap);
- va_end(ap);
-}
-
-void
-vmmdev_init(void)
-{
- vmm_trace_rbuf_alloc();
-}
-
-int
-vmmdev_cleanup(void)
-{
- VERIFY(list_is_empty(&vmmdev_list));
-
- vmm_trace_dmsg_free();
- return (0);
-}
-
static int
vmmdev_get_memseg(vmm_softc_t *sc, struct vm_memseg *mseg)
{
diff --git a/usr/src/uts/i86pc/sys/vmm_dev.h b/usr/src/uts/i86pc/sys/vmm_dev.h
index d9cb23ece9..e037089239 100644
--- a/usr/src/uts/i86pc/sys/vmm_dev.h
+++ b/usr/src/uts/i86pc/sys/vmm_dev.h
@@ -42,11 +42,6 @@
#ifndef _VMM_DEV_H_
#define _VMM_DEV_H_
-#ifdef _KERNEL
-void vmmdev_init(void);
-int vmmdev_cleanup(void);
-#endif
-
struct vm_memmap {
vm_paddr_t gpa;
int segid; /* memory segment */
diff --git a/usr/src/uts/i86pc/sys/vmm_impl.h b/usr/src/uts/i86pc/sys/vmm_impl.h
index 4d5708e48d..db2c4ab991 100644
--- a/usr/src/uts/i86pc/sys/vmm_impl.h
+++ b/usr/src/uts/i86pc/sys/vmm_impl.h
@@ -78,37 +78,4 @@ int vmm_do_vm_destroy(vmm_softc_t *, boolean_t);
#endif /* _KERNEL */
-/*
- * VMM trace ring buffer constants
- */
-#define VMM_DMSG_RING_SIZE 0x100000 /* 1MB */
-#define VMM_DMSG_BUF_SIZE 256
-
-/*
- * VMM trace ring buffer content
- */
-typedef struct vmm_trace_dmsg {
- timespec_t timestamp;
- char buf[VMM_DMSG_BUF_SIZE];
- struct vmm_trace_dmsg *next;
-} vmm_trace_dmsg_t;
-
-/*
- * VMM trace ring buffer header
- */
-typedef struct vmm_trace_rbuf {
- kmutex_t lock; /* lock to avoid clutter */
- int looped; /* completed ring */
- int allocfailed; /* dmsg mem alloc failed */
- size_t size; /* current size */
- size_t maxsize; /* max size */
- vmm_trace_dmsg_t *dmsgh; /* messages head */
- vmm_trace_dmsg_t *dmsgp; /* ptr to last message */
-} vmm_trace_rbuf_t;
-
-/*
- * VMM trace ring buffer interfaces
- */
-void vmm_trace_log(const char *fmt, ...);
-
#endif /* _VMM_IMPL_H_ */