⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 console.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** * console.c *  * Emergency console I/O for Xen and the domain-0 guest OS. *  * Copyright (c) 2002-2004, K A Fraser. * * Added printf_ratelimit *     Taken from Linux - Author: Andi Kleen (net_ratelimit) *     Ported to Xen - Steven Rostedt - Red Hat */#include <xen/stdarg.h>#include <xen/config.h>#include <xen/version.h>#include <xen/init.h>#include <xen/lib.h>#include <xen/errno.h>#include <xen/event.h>#include <xen/spinlock.h>#include <xen/console.h>#include <xen/serial.h>#include <xen/softirq.h>#include <xen/keyhandler.h>#include <xen/mm.h>#include <xen/delay.h>#include <xen/guest_access.h>#include <xen/shutdown.h>#include <xen/vga.h>#include <xen/kexec.h>#include <asm/current.h>#include <asm/debugger.h>#include <asm/io.h>#include <asm/div64.h>#include <xsm/xsm.h>#include <public/sysctl.h>/* console: comma-separated list of console outputs. */static char opt_console[30] = OPT_CONSOLE_STR;string_param("console", opt_console);/* conswitch: a character pair controlling console switching. *//* Char 1: CTRL+<char1> is used to switch console input between Xen and DOM0 *//* Char 2: If this character is 'x', then do not auto-switch to DOM0 when it *//*         boots. Any other value, or omitting the char, enables auto-switch */static unsigned char opt_conswitch[3] = "a";string_param("conswitch", opt_conswitch);/* sync_console: force synchronous console output (useful for debugging). */static int opt_sync_console;boolean_param("sync_console", opt_sync_console);/* console_to_ring: send guest (incl. dom 0) console data to console ring. */static int opt_console_to_ring;boolean_param("console_to_ring", opt_console_to_ring);/* console_timestamps: include a timestamp prefix on every Xen console line. */static int opt_console_timestamps;boolean_param("console_timestamps", opt_console_timestamps);#define CONRING_SIZE 16384#define CONRING_IDX_MASK(i) ((i)&(CONRING_SIZE-1))static char conring[CONRING_SIZE];static uint32_t conringc, conringp;static int sercon_handle = -1;static DEFINE_SPINLOCK(console_lock);/* * To control the amount of printing, thresholds are added. * These thresholds correspond to the XENLOG logging levels. * There's an upper and lower threshold for non-guest messages and for * guest-provoked messages.  This works as follows, for a given log level L: * * L < lower_threshold                     : always logged * lower_threshold <= L < upper_threshold  : rate-limited logging * upper_threshold <= L                    : never logged * * Note, in the above algorithm, to disable rate limiting simply make * the lower threshold equal to the upper. */#ifdef NDEBUG#define XENLOG_UPPER_THRESHOLD       2 /* Do not print INFO and DEBUG  */#define XENLOG_LOWER_THRESHOLD       2 /* Always print ERR and WARNING */#define XENLOG_GUEST_UPPER_THRESHOLD 2 /* Do not print INFO and DEBUG  */#define XENLOG_GUEST_LOWER_THRESHOLD 0 /* Rate-limit ERR and WARNING   */#else#define XENLOG_UPPER_THRESHOLD       4 /* Do not discard anything      */#define XENLOG_LOWER_THRESHOLD       4 /* Print everything             */#define XENLOG_GUEST_UPPER_THRESHOLD 4 /* Do not discard anything      */#define XENLOG_GUEST_LOWER_THRESHOLD 4 /* Print everything             */#endif/* * The XENLOG_DEFAULT is the default given to printks that * do not have any print level associated with them. */#define XENLOG_DEFAULT       1 /* XENLOG_WARNING */#define XENLOG_GUEST_DEFAULT 1 /* XENLOG_WARNING */static int xenlog_upper_thresh = XENLOG_UPPER_THRESHOLD;static int xenlog_lower_thresh = XENLOG_LOWER_THRESHOLD;static int xenlog_guest_upper_thresh = XENLOG_GUEST_UPPER_THRESHOLD;static int xenlog_guest_lower_thresh = XENLOG_GUEST_LOWER_THRESHOLD;static void parse_loglvl(char *s);static void parse_guest_loglvl(char *s);/* * <lvl> := none|error|warning|info|debug|all * loglvl=<lvl_print_always>[/<lvl_print_ratelimit>] *  <lvl_print_always>: log level which is always printed *  <lvl_print_rlimit>: log level which is rate-limit printed * Similar definitions for guest_loglvl, but applies to guest tracing. * Defaults: loglvl=warning ; guest_loglvl=none/warning */custom_param("loglvl", parse_loglvl);custom_param("guest_loglvl", parse_guest_loglvl);static atomic_t print_everything = ATOMIC_INIT(0);#define ___parse_loglvl(s, ps, lvlstr, lvlnum)          \    if ( !strncmp((s), (lvlstr), strlen(lvlstr)) ) {    \        *(ps) = (s) + strlen(lvlstr);                   \        return (lvlnum);                                \    }static int __init __parse_loglvl(char *s, char **ps){    ___parse_loglvl(s, ps, "none",    0);    ___parse_loglvl(s, ps, "error",   1);    ___parse_loglvl(s, ps, "warning", 2);    ___parse_loglvl(s, ps, "info",    3);    ___parse_loglvl(s, ps, "debug",   4);    ___parse_loglvl(s, ps, "all",     4);    return 2; /* sane fallback */}static void __init _parse_loglvl(char *s, int *lower, int *upper){    *lower = *upper = __parse_loglvl(s, &s);    if ( *s == '/' )        *upper = __parse_loglvl(s+1, &s);    if ( *upper < *lower )        *upper = *lower;}static void __init parse_loglvl(char *s){    _parse_loglvl(s, &xenlog_lower_thresh, &xenlog_upper_thresh);}static void __init parse_guest_loglvl(char *s){    _parse_loglvl(s, &xenlog_guest_lower_thresh, &xenlog_guest_upper_thresh);}static char * __init loglvl_str(int lvl){    switch ( lvl )    {    case 0: return "Nothing";    case 1: return "Errors";    case 2: return "Errors and warnings";    case 3: return "Errors, warnings and info";    case 4: return "All";    }    return "???";}/* * ******************************************************** * *************** ACCESS TO CONSOLE RING ***************** * ******************************************************** */static void putchar_console_ring(int c){    ASSERT(spin_is_locked(&console_lock));    conring[CONRING_IDX_MASK(conringp++)] = c;    if ( (uint32_t)(conringp - conringc) > CONRING_SIZE )        conringc = conringp - CONRING_SIZE;}long read_console_ring(struct xen_sysctl_readconsole *op){    XEN_GUEST_HANDLE(char) str;    uint32_t idx, len, max, sofar, c;    str   = guest_handle_cast(op->buffer, char),    max   = op->count;    sofar = 0;    c = conringc;    if ( op->incremental && ((int32_t)(op->index - c) < 0) )        c = op->index;    while ( (c != conringp) && (sofar < max) )    {        idx = CONRING_IDX_MASK(c);        len = conringp - c;        if ( (idx + len) > CONRING_SIZE )            len = CONRING_SIZE - idx;        if ( (sofar + len) > max )            len = max - sofar;        if ( copy_to_guest_offset(str, sofar, &conring[idx], len) )            return -EFAULT;        sofar += len;        c += len;    }    if ( op->clear )    {        spin_lock_irq(&console_lock);        if ( (uint32_t)(conringp - c) > CONRING_SIZE )            conringc = conringp - CONRING_SIZE;        else            conringc = c;        spin_unlock_irq(&console_lock);    }    op->count = sofar;    op->index = c;    return 0;}/* * ******************************************************* * *************** ACCESS TO SERIAL LINE ***************** * ******************************************************* *//* Characters received over the serial line are buffered for domain 0. */#define SERIAL_RX_SIZE 128#define SERIAL_RX_MASK(_i) ((_i)&(SERIAL_RX_SIZE-1))static char serial_rx_ring[SERIAL_RX_SIZE];static unsigned int serial_rx_cons, serial_rx_prod;static void (*serial_steal_fn)(const char *);int console_steal(int handle, void (*fn)(const char *)){    if ( (handle == -1) || (handle != sercon_handle) )        return 0;    if ( serial_steal_fn != NULL )        return -EBUSY;    serial_steal_fn = fn;    return 1;}void console_giveback(int id){    if ( id == 1 )        serial_steal_fn = NULL;}static void sercon_puts(const char *s){    if ( serial_steal_fn != NULL )        (*serial_steal_fn)(s);    else        serial_puts(sercon_handle, s);}/* CTRL-<switch_char> switches input direction between Xen and DOM0. */#define switch_code (opt_conswitch[0]-'a'+1)static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */static void switch_serial_input(void){    static char *input_str[2] = { "DOM0", "Xen" };    xen_rx = !xen_rx;    printk("*** Serial input -> %s", input_str[xen_rx]);    if ( switch_code )        printk(" (type 'CTRL-%c' three times to switch input to %s)",               opt_conswitch[0], input_str[!xen_rx]);    printk("\n");}static void __serial_rx(char c, struct cpu_user_regs *regs){    if ( xen_rx )        return handle_keypress(c, regs);    /* Deliver input to guest buffer, unless it is already full. */    if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )        serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;    /* Always notify the guest: prevents receive path from getting stuck. */    send_guest_global_virq(dom0, VIRQ_CONSOLE);}static void serial_rx(char c, struct cpu_user_regs *regs){    static int switch_code_count = 0;    if ( switch_code && (c == switch_code) )    {        /* We eat CTRL-<switch_char> in groups of 3 to switch console input. */        if ( ++switch_code_count == 3 )        {            switch_serial_input();            switch_code_count = 0;        }        return;    }    for ( ; switch_code_count != 0; switch_code_count-- )        __serial_rx(switch_code, regs);    /* Finally process the just-received character. */    __serial_rx(c, regs);}static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count){    char kbuf[128], *kptr;    int kcount;    while ( count > 0 )    {        while ( serial_tx_space(sercon_handle) < (serial_txbufsz / 2) )        {            if ( hypercall_preempt_check() )                break;            cpu_relax();        }        if ( hypercall_preempt_check() )            return hypercall_create_continuation(                __HYPERVISOR_console_io, "iih",                CONSOLEIO_write, count, buffer);        kcount = min_t(int, count, sizeof(kbuf)-1);        if ( copy_from_guest(kbuf, buffer, kcount) )            return -EFAULT;        kbuf[kcount] = '\0';        spin_lock_irq(&console_lock);        sercon_puts(kbuf);        vga_puts(kbuf);        if ( opt_console_to_ring )        {            for ( kptr = kbuf; *kptr != '\0'; kptr++ )                putchar_console_ring(*kptr);            send_guest_global_virq(dom0, VIRQ_CON_RING);        }        spin_unlock_irq(&console_lock);        guest_handle_add_offset(buffer, kcount);        count -= kcount;    }    return 0;}long do_console_io(int cmd, int count, XEN_GUEST_HANDLE(char) buffer){    long rc;    unsigned int idx, len;#ifndef VERBOSE    /* Only domain 0 may access the emergency console. */    if ( current->domain->domain_id != 0 )        return -EPERM;#endif    rc = xsm_console_io(current->domain, cmd);    if ( rc )        return rc;    switch ( cmd )    {    case CONSOLEIO_write:        rc = guest_console_write(buffer, count);        break;    case CONSOLEIO_read:        rc = 0;        while ( (serial_rx_cons != serial_rx_prod) && (rc < count) )        {            idx = SERIAL_RX_MASK(serial_rx_cons);            len = serial_rx_prod - serial_rx_cons;            if ( (idx + len) > SERIAL_RX_SIZE )                len = SERIAL_RX_SIZE - idx;            if ( (rc + len) > count )                len = count - rc;            if ( copy_to_guest_offset(buffer, rc, &serial_rx_ring[idx], len) )            {                rc = -EFAULT;                break;            }            rc += len;            serial_rx_cons += len;        }        break;    default:        rc = -ENOSYS;        break;    }    return rc;}/* * ***************************************************** * *************** GENERIC CONSOLE I/O ***************** * ***************************************************** */static void __putstr(const char *str){    int c;    ASSERT(spin_is_locked(&console_lock));    sercon_puts(str);    vga_puts(str);    while ( (c = *str++) != '\0' )        putchar_console_ring(c);    send_guest_global_virq(dom0, VIRQ_CON_RING);}static int printk_prefix_check(char *p, char **pp){    int loglvl = -1;    int upper_thresh = xenlog_upper_thresh;    int lower_thresh = xenlog_lower_thresh;    while ( (p[0] == '<') && (p[1] != '\0') && (p[2] == '>') )    {        switch ( p[1] )        {        case 'G':            upper_thresh = xenlog_guest_upper_thresh;            lower_thresh = xenlog_guest_lower_thresh;            if ( loglvl == -1 )                loglvl = XENLOG_GUEST_DEFAULT;            break;        case '0' ... '3':            loglvl = p[1] - '0';            break;        }        p += 3;    }    if ( loglvl == -1 )        loglvl = XENLOG_DEFAULT;    *pp = p;    return ((atomic_read(&print_everything) != 0) ||            (loglvl < lower_thresh) ||            ((loglvl < upper_thresh) && printk_ratelimit()));} static void printk_start_of_line(void){    struct tm tm;    char tstr[32];    __putstr("(XEN) ");    if ( !opt_console_timestamps )        return;    tm = wallclock_time();    if ( tm.tm_mday == 0 )        return;    snprintf(tstr, sizeof(tstr), "[%04u-%02u-%02u %02u:%02u:%02u] ",             1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,             tm.tm_hour, tm.tm_min, tm.tm_sec);    __putstr(tstr);}void printk(const char *fmt, ...){    static char   buf[1024];    static int    start_of_line = 1, do_print;    va_list       args;    char         *p, *q;    unsigned long flags;    /* console_lock can be acquired recursively from __printk_ratelimit(). */    local_irq_save(flags);    spin_lock_recursive(&console_lock);    va_start(args, fmt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -