The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/dcons/dcons_os.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (C) 2003,2004
    3  *      Hidetoshi Shimokawa. All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *
   16  *      This product includes software developed by Hidetoshi Shimokawa.
   17  *
   18  * 4. Neither the name of the author nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  * $FreeBSD: releng/9.0/sys/dev/dcons/dcons_os.c 225214 2011-08-27 14:24:27Z rwatson $
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/kdb.h>
   39 #include <gdb/gdb.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 #include <sys/systm.h>
   43 #include <sys/types.h>
   44 #include <sys/conf.h>
   45 #include <sys/cons.h>
   46 #include <sys/consio.h>
   47 #include <sys/tty.h>
   48 #include <sys/malloc.h>
   49 #include <sys/priv.h>
   50 #include <sys/proc.h>
   51 #include <sys/ucred.h>
   52 
   53 #include <machine/bus.h>
   54 
   55 #include <dev/dcons/dcons.h>
   56 #include <dev/dcons/dcons_os.h>
   57 
   58 #include <ddb/ddb.h>
   59 #include <sys/reboot.h>
   60 
   61 #include <sys/sysctl.h>
   62 
   63 #include <vm/vm.h>
   64 #include <vm/vm_param.h>
   65 #include <vm/pmap.h>
   66 
   67 #include "opt_dcons.h"
   68 #include "opt_kdb.h"
   69 #include "opt_gdb.h"
   70 #include "opt_ddb.h"
   71 
   72 
   73 #ifndef DCONS_POLL_HZ
   74 #define DCONS_POLL_HZ   25
   75 #endif
   76 
   77 #ifndef DCONS_BUF_SIZE
   78 #define DCONS_BUF_SIZE (16*1024)
   79 #endif
   80 
   81 #ifndef DCONS_FORCE_CONSOLE
   82 #define DCONS_FORCE_CONSOLE     0       /* Mostly for FreeBSD-4/DragonFly */
   83 #endif
   84 
   85 #ifndef KLD_MODULE
   86 static char bssbuf[DCONS_BUF_SIZE];     /* buf in bss */
   87 #endif
   88 
   89 /* global data */
   90 static struct dcons_global dg;
   91 struct dcons_global *dcons_conf;
   92 static int poll_hz = DCONS_POLL_HZ;
   93 
   94 static struct dcons_softc sc[DCONS_NPORT];
   95 
   96 SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console");
   97 SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0,
   98                                 "dcons polling rate");
   99 
  100 static int drv_init = 0;
  101 static struct callout dcons_callout;
  102 struct dcons_buf *dcons_buf;            /* for local dconschat */
  103 
  104 static void     dcons_timeout(void *);
  105 static int      dcons_drv_init(int);
  106 
  107 static cn_probe_t       dcons_cnprobe;
  108 static cn_init_t        dcons_cninit;
  109 static cn_term_t        dcons_cnterm;
  110 static cn_getc_t        dcons_cngetc;
  111 static cn_putc_t        dcons_cnputc;
  112 
  113 CONSOLE_DRIVER(dcons);
  114 
  115 #if defined(GDB)
  116 static gdb_probe_f      dcons_dbg_probe;
  117 static gdb_init_f       dcons_dbg_init;
  118 static gdb_term_f       dcons_dbg_term;
  119 static gdb_getc_f       dcons_dbg_getc;
  120 static gdb_putc_f       dcons_dbg_putc;
  121 
  122 GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term,
  123     dcons_dbg_getc, dcons_dbg_putc);
  124 
  125 extern struct gdb_dbgport *gdb_cur;
  126 #endif
  127 
  128 static tsw_outwakeup_t dcons_outwakeup;
  129 
  130 static struct ttydevsw dcons_ttydevsw = {
  131         .tsw_flags      = TF_NOPREFIX,
  132         .tsw_outwakeup  = dcons_outwakeup,
  133 };
  134 
  135 #if (defined(GDB) || defined(DDB))
  136 static int
  137 dcons_check_break(struct dcons_softc *dc, int c)
  138 {
  139 
  140         if (c < 0)
  141                 return (c);
  142 
  143 #ifdef GDB
  144         if ((dc->flags & DC_GDB) != 0 && gdb_cur == &dcons_gdb_dbgport)
  145                 kdb_alt_break_gdb(c, &dc->brk_state);
  146         else
  147 #endif
  148                 kdb_alt_break(c, &dc->brk_state);
  149 
  150         return (c);
  151 }
  152 #else
  153 #define dcons_check_break(dc, c)        (c)
  154 #endif
  155 
  156 static int
  157 dcons_os_checkc_nopoll(struct dcons_softc *dc)
  158 {
  159         int c;
  160 
  161         if (dg.dma_tag != NULL)
  162                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD);
  163 
  164         c = dcons_check_break(dc, dcons_checkc(dc));
  165 
  166         if (dg.dma_tag != NULL)
  167                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREREAD);
  168 
  169         return (c);
  170 }
  171 
  172 static int
  173 dcons_os_checkc(struct dcons_softc *dc)
  174 {
  175         EVENTHANDLER_INVOKE(dcons_poll, 0);
  176         return (dcons_os_checkc_nopoll(dc));
  177 }
  178 
  179 static void
  180 dcons_os_putc(struct dcons_softc *dc, int c)
  181 {
  182         if (dg.dma_tag != NULL)
  183                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTWRITE);
  184 
  185         dcons_putc(dc, c);
  186 
  187         if (dg.dma_tag != NULL)
  188                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE);
  189 }
  190 
  191 static void
  192 dcons_outwakeup(struct tty *tp)
  193 {
  194         struct dcons_softc *dc;
  195         char ch;
  196 
  197         dc = tty_softc(tp);
  198 
  199         while (ttydisc_getc(tp, &ch, sizeof ch) != 0)
  200                 dcons_os_putc(dc, ch);
  201 }
  202 
  203 static void
  204 dcons_timeout(void *v)
  205 {
  206         struct  tty *tp;
  207         struct dcons_softc *dc;
  208         int i, c, polltime;
  209 
  210         for (i = 0; i < DCONS_NPORT; i ++) {
  211                 dc = &sc[i];
  212                 tp = dc->tty;
  213 
  214                 tty_lock(tp);
  215                 while ((c = dcons_os_checkc_nopoll(dc)) != -1)
  216                         ttydisc_rint(tp, c, 0);
  217                 ttydisc_rint_done(tp);
  218                 tty_unlock(tp);
  219         }
  220         polltime = hz / poll_hz;
  221         if (polltime < 1)
  222                 polltime = 1;
  223         callout_reset(&dcons_callout, polltime, dcons_timeout, tp);
  224 }
  225 
  226 static void
  227 dcons_cnprobe(struct consdev *cp)
  228 {
  229         sprintf(cp->cn_name, "dcons");
  230 #if DCONS_FORCE_CONSOLE
  231         cp->cn_pri = CN_REMOTE;
  232 #else
  233         cp->cn_pri = CN_NORMAL;
  234 #endif
  235 }
  236 
  237 static void
  238 dcons_cninit(struct consdev *cp)
  239 {
  240         dcons_drv_init(0);
  241         cp->cn_arg = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
  242 }
  243 
  244 static void
  245 dcons_cnterm(struct consdev *cp)
  246 {
  247 }
  248 
  249 static int
  250 dcons_cngetc(struct consdev *cp)
  251 {
  252         struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
  253         return (dcons_os_checkc(dc));
  254 }
  255 
  256 static void
  257 dcons_cnputc(struct consdev *cp, int c)
  258 {
  259         struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
  260         dcons_os_putc(dc, c);
  261 }
  262 
  263 static int
  264 dcons_drv_init(int stage)
  265 {
  266 #if defined(__i386__) || defined(__amd64__)
  267         quad_t addr, size;
  268 #endif
  269 
  270         if (drv_init)
  271                 return(drv_init);
  272 
  273         drv_init = -1;
  274 
  275         bzero(&dg, sizeof(dg));
  276         dcons_conf = &dg;
  277         dg.cdev = &dcons_consdev;
  278         dg.buf = NULL;
  279         dg.size = DCONS_BUF_SIZE;
  280 
  281 #if defined(__i386__) || defined(__amd64__)
  282         if (getenv_quad("dcons.addr", &addr) > 0 &&
  283             getenv_quad("dcons.size", &size) > 0) {
  284 #ifdef __i386__
  285                 vm_paddr_t pa;
  286                 /*
  287                  * Allow read/write access to dcons buffer.
  288                  */
  289                 for (pa = trunc_page(addr); pa < addr + size; pa += PAGE_SIZE)
  290                         *vtopte(KERNBASE + pa) |= PG_RW;
  291                 invltlb();
  292 #endif
  293                 /* XXX P to V */
  294                 dg.buf = (struct dcons_buf *)(vm_offset_t)(KERNBASE + addr);
  295                 dg.size = size;
  296                 if (dcons_load_buffer(dg.buf, dg.size, sc) < 0)
  297                         dg.buf = NULL;
  298         }
  299 #endif
  300         if (dg.buf != NULL)
  301                 goto ok;
  302 
  303 #ifndef KLD_MODULE
  304         if (stage == 0) { /* XXX or cold */
  305                 /*
  306                  * DCONS_FORCE_CONSOLE == 1 and statically linked.
  307                  * called from cninit(). can't use contigmalloc yet .
  308                  */
  309                 dg.buf = (struct dcons_buf *) bssbuf;
  310                 dcons_init(dg.buf, dg.size, sc);
  311         } else
  312 #endif
  313         {
  314                 /*
  315                  * DCONS_FORCE_CONSOLE == 0 or kernel module case.
  316                  * if the module is loaded after boot,
  317                  * bssbuf could be non-continuous.
  318                  */ 
  319                 dg.buf = (struct dcons_buf *) contigmalloc(dg.size,
  320                         M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
  321                 if (dg.buf == NULL)
  322                         return (-1);
  323                 dcons_init(dg.buf, dg.size, sc);
  324         }
  325 
  326 ok:
  327         dcons_buf = dg.buf;
  328 
  329         drv_init = 1;
  330 
  331         return 0;
  332 }
  333 
  334 
  335 static int
  336 dcons_attach_port(int port, char *name, int flags)
  337 {
  338         struct dcons_softc *dc;
  339         struct tty *tp;
  340 
  341         dc = &sc[port];
  342         tp = tty_alloc(&dcons_ttydevsw, dc);
  343         dc->flags = flags;
  344         dc->tty   = tp;
  345         tty_init_console(tp, 0);
  346         tty_makedev(tp, NULL, "%s", name);
  347         return(0);
  348 }
  349 
  350 static int
  351 dcons_attach(void)
  352 {
  353         int polltime;
  354 
  355         dcons_attach_port(DCONS_CON, "dcons", 0);
  356         dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB);
  357         callout_init(&dcons_callout, CALLOUT_MPSAFE);
  358         polltime = hz / poll_hz;
  359         if (polltime < 1)
  360                 polltime = 1;
  361         callout_reset(&dcons_callout, polltime, dcons_timeout, NULL);
  362         return(0);
  363 }
  364 
  365 static int
  366 dcons_detach(int port)
  367 {
  368         struct  tty *tp;
  369         struct dcons_softc *dc;
  370 
  371         dc = &sc[port];
  372         tp = dc->tty;
  373 
  374         tty_lock(tp);
  375         tty_rel_gone(tp);
  376 
  377         return(0);
  378 }
  379 
  380 static int
  381 dcons_modevent(module_t mode, int type, void *data)
  382 {
  383         int err = 0, ret;
  384 
  385         switch (type) {
  386         case MOD_LOAD:
  387                 ret = dcons_drv_init(1);
  388                 if (ret != -1)
  389                         dcons_attach();
  390                 if (ret == 0) {
  391                         dcons_cnprobe(&dcons_consdev);
  392                         dcons_cninit(&dcons_consdev);
  393                         cnadd(&dcons_consdev);
  394                 }
  395                 break;
  396         case MOD_UNLOAD:
  397                 printf("dcons: unload\n");
  398                 if (drv_init == 1) {
  399                         callout_stop(&dcons_callout);
  400                         cnremove(&dcons_consdev);
  401                         dcons_detach(DCONS_CON);
  402                         dcons_detach(DCONS_GDB);
  403                         dg.buf->magic = 0;
  404 
  405                         contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF);
  406                 }
  407 
  408                 break;
  409         case MOD_SHUTDOWN:
  410 #if 0           /* Keep connection after halt */
  411                 dg.buf->magic = 0;
  412 #endif
  413                 break;
  414         default:
  415                 err = EOPNOTSUPP;
  416                 break;
  417         }
  418         return(err);
  419 }
  420 
  421 #if defined(GDB)
  422 /* Debugger interface */
  423 
  424 static int
  425 dcons_os_getc(struct dcons_softc *dc)
  426 {
  427         int c;
  428 
  429         while ((c = dcons_os_checkc(dc)) == -1);
  430 
  431         return (c & 0xff);
  432 }
  433 
  434 static int
  435 dcons_dbg_probe(void)
  436 {
  437         int dcons_gdb;
  438 
  439         if (getenv_int("dcons_gdb", &dcons_gdb) == 0)
  440                 return (-1);
  441         return (dcons_gdb);
  442 }
  443 
  444 static void
  445 dcons_dbg_init(void)
  446 {
  447 }
  448 
  449 static void
  450 dcons_dbg_term(void)
  451 {
  452 }
  453 
  454 static void
  455 dcons_dbg_putc(int c)
  456 {
  457         struct dcons_softc *dc = &sc[DCONS_GDB];
  458         dcons_os_putc(dc, c);
  459 }
  460 
  461 static int
  462 dcons_dbg_getc(void)
  463 {
  464         struct dcons_softc *dc = &sc[DCONS_GDB];
  465         return (dcons_os_getc(dc));
  466 }
  467 #endif
  468 
  469 DEV_MODULE(dcons, dcons_modevent, NULL);
  470 MODULE_VERSION(dcons, DCONS_VERSION);

Cache object: f83be54646c3e92d37e43d6fdb8c22b0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.