1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * PROM interface
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <unistd.h>
  33 #include <string.h>
  34 #include <stdlib.h>
  35 
  36 #define _KERNEL
  37 #define _BOOT
  38 #include <sys/promif.h>
  39 #undef _BOOT
  40 #undef _KERNEL
  41 
  42 #include <mdb/mdb_debug.h>
  43 #include <mdb/mdb_err.h>
  44 #include <kmdb/kmdb_promif_impl.h>
  45 #include <kmdb/kmdb_kdi.h>
  46 #include <mdb/mdb_string.h>
  47 #include <mdb/mdb.h>
  48 
  49 #ifndef sun4v
  50 int kmdb_prom_preserve_kctx = 0;
  51 #endif /* sun4v */
  52 
  53 ssize_t
  54 kmdb_prom_obp_writer(caddr_t buf, size_t len)
  55 {
  56         return (prom_write(prom_stdout_ihandle(), buf, len, 0, 0));
  57 }
  58 
  59 ihandle_t
  60 kmdb_prom_get_handle(char *name)
  61 {
  62         if (strcmp(name, "stdin") == 0)
  63                 return (prom_stdin_ihandle());
  64         else if (strcmp(name, "stdout") == 0 || strcmp(name, "stderr") == 0)
  65                 return (prom_stdout_ihandle());
  66         else
  67                 return (-1);
  68 }
  69 
  70 /*ARGSUSED*/
  71 char *
  72 kmdb_prom_get_ddi_prop(kmdb_auxv_t *kav, char *propname)
  73 {
  74         pnode_t node;
  75         ssize_t len;
  76         char *val;
  77 
  78         if ((node = prom_finddevice("/options")) == NULL)
  79                 return (NULL);
  80 
  81         if ((len = prom_getproplen(node, propname)) < 0)
  82                 return (NULL);
  83 
  84         val = mdb_alloc(len + 1, UM_SLEEP);
  85 
  86         if (prom_bounded_getprop(node, propname, val, len) != len) {
  87                 mdb_free(val, len);
  88                 return (NULL);
  89         }
  90         val[len] = '\0';
  91 
  92         return (val);
  93 }
  94 
  95 void
  96 kmdb_prom_free_ddi_prop(char *val)
  97 {
  98         strfree(val);
  99 }
 100 
 101 int
 102 kmdb_prom_getprop(pnode_t node, char *name, caddr_t value)
 103 {
 104         return (prom_getprop(node, name, value));
 105 }
 106 
 107 /*ARGSUSED*/
 108 void
 109 kmdb_prom_get_tem_size(kmdb_auxv_t *kav, ushort_t *rows, ushort_t *cols)
 110 {
 111         /* We fall back to defaults for now. */
 112 }
 113 
 114 typedef struct walk_cpu_data {
 115         int (*wcd_cb)(pnode_t, void *, void *);
 116         void *wcd_arg;
 117 } walk_cpu_data_t;
 118 
 119 static int
 120 walk_cpus_cb(pnode_t node, void *arg, void *result)
 121 {
 122         walk_cpu_data_t *wcd = arg;
 123 
 124         /*
 125          * Sun4v doesn't support port_id on guest.
 126          */
 127 #ifndef sun4v
 128         int port_id;
 129 #endif  /* sun4v */
 130 
 131         if (!prom_devicetype(node, OBP_CPU))
 132                 return (PROM_WALK_CONTINUE);
 133 
 134 #ifndef sun4v
 135         if ((prom_getprop(node, "portid", (caddr_t)&port_id) == -1) &&
 136             (prom_getprop(node, "upa-portid", (caddr_t)&port_id) == -1) &&
 137             (prom_getprop(node, "cpuid", (caddr_t)&port_id) == -1)) {
 138                 warn("cpu node %x has no identifying properties\n",
 139                     node);
 140                 return (PROM_WALK_CONTINUE);
 141         }
 142 #endif  /* sun4v */
 143 
 144         if (wcd->wcd_cb(node, wcd->wcd_arg, result) != 0)
 145                 return (PROM_WALK_TERMINATE);
 146 
 147         return (PROM_WALK_CONTINUE);
 148 }
 149 
 150 void
 151 kmdb_prom_walk_cpus(int (*cb)(pnode_t, void *, void *), void *arg, void *result)
 152 {
 153         walk_cpu_data_t wcd;
 154 
 155         wcd.wcd_cb = cb;
 156         wcd.wcd_arg = arg;
 157 
 158         prom_walk_devs(prom_rootnode(), walk_cpus_cb, &wcd, result);
 159 }
 160 
 161 void
 162 kmdb_prom_enter_mon(void)
 163 {
 164         prom_enter_mon();
 165 }
 166 
 167 #ifndef sun4v
 168 pnode_t
 169 kmdb_prom_getcpu_propnode(pnode_t node)
 170 {
 171         int val;
 172         pnode_t pnode;
 173         char name[OBP_MAXPROPNAME];
 174 
 175 
 176         /*
 177          * Check for the CMT case where cpu nodes are "strand" nodes
 178          * In this case, the "cpu node" properties are contained in
 179          * its parent "core" node.
 180          */
 181         if (prom_getprop(node, "portid", (caddr_t)&val) == -1 &&
 182             prom_getprop(node, "upa-portid", (caddr_t)&val) == -1 &&
 183             prom_getprop((pnode = prom_parentnode(node)), "name", name) != -1 &&
 184             strcmp(name, "core") == 0)
 185                 return (pnode);
 186 
 187         return (node);
 188 }
 189 #endif  /* sun4v */
 190 
 191 void
 192 kmdb_prom_exit_to_mon(void)
 193 {
 194         prom_exit_to_mon();
 195 }
 196 
 197 void
 198 kmdb_prom_interpret(const char *str)
 199 {
 200         prom_interpret((char *)str, 0, 0, 0, 0, 0);
 201 }
 202 
 203 /*ARGSUSED*/
 204 int
 205 kmdb_prom_translate_virt(uintptr_t virt, physaddr_t *pap)
 206 {
 207         extern int prom_translate_virt(caddr_t, int *, u_longlong_t *, int *);
 208 
 209         int valid, mode;
 210         uintptr_t vabase = virt & ~(mdb.m_pagesize - 1);
 211         uintptr_t off = virt - vabase;
 212         u_longlong_t pa;
 213 
 214         mdb_dprintf(MDB_DBG_DPI, "using OBP for vtop of %p\n", (void *)virt);
 215 
 216         if (prom_translate_virt((caddr_t)vabase, &valid, &pa, &mode) != 0)
 217                 return (set_errno(EMDB_NOMAP));
 218 
 219         *pap = pa + off;
 220         return (0);
 221 }
 222 
 223 /*ARGSUSED*/
 224 int
 225 kmdb_prom_stdout_is_framebuffer(kmdb_auxv_t *kav)
 226 {
 227         return (prom_stdout_is_framebuffer());
 228 }
 229 
 230 #ifndef sun4v
 231 #define PROM_KCTX_PRESERVED_PROPNAME    "context0-page-size-preserved"
 232 void
 233 kmdb_prom_preserve_kctx_init(void)
 234 {
 235         pnode_t pnode;
 236         int     val;
 237 
 238         pnode = (pnode_t)prom_getphandle(prom_mmu_ihandle());
 239         if (prom_getprop(pnode, PROM_KCTX_PRESERVED_PROPNAME,
 240             (caddr_t)&val) == 0) {
 241                 kmdb_prom_preserve_kctx = 1;
 242         }
 243 }
 244 #endif /* sun4v */