stdvga.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 634 行 · 第 1/2 页

C
634
字号
/* *  Copyright (c) 2003-2007, Virtual Iron Software, Inc. * *  Portions have been modified by Virtual Iron Software, Inc. *  (c) 2007. This file and the modifications can be redistributed and/or *  modified under the terms and conditions of the GNU General Public *  License, version 2.1 and not any later version of the GPL, as published *  by the Free Software Foundation.  * *  This improves the performance of Standard VGA, *  the mode used during Windows boot and by the Linux *  splash screen. * *  It does so by buffering all the stdvga programmed output ops *  and memory mapped ops (both reads and writes) that are sent to QEMU. * *  We maintain locally essential VGA state so we can respond *  immediately to input and read ops without waiting for *  QEMU.  We snoop output and write ops to keep our state *  up-to-date. * *  PIO input ops are satisfied from cached state without *  bothering QEMU. * *  PIO output and mmio ops are passed through to QEMU, including *  mmio read ops.  This is necessary because mmio reads *  can have side effects. */#include <xen/config.h>#include <xen/types.h>#include <xen/sched.h>#include <xen/domain_page.h>#include <asm/hvm/support.h>#include <xen/numa.h>#include <xen/paging.h>#define VGA_MEM_BASE 0xa0000#define VGA_MEM_SIZE 0x20000#define PAT(x) (x)static const uint32_t mask16[16] = {    PAT(0x00000000),    PAT(0x000000ff),    PAT(0x0000ff00),    PAT(0x0000ffff),    PAT(0x00ff0000),    PAT(0x00ff00ff),    PAT(0x00ffff00),    PAT(0x00ffffff),    PAT(0xff000000),    PAT(0xff0000ff),    PAT(0xff00ff00),    PAT(0xff00ffff),    PAT(0xffff0000),    PAT(0xffff00ff),    PAT(0xffffff00),    PAT(0xffffffff),};/* force some bits to zero */const uint8_t sr_mask[8] = {    (uint8_t)~0xfc,    (uint8_t)~0xc2,    (uint8_t)~0xf0,    (uint8_t)~0xc0,    (uint8_t)~0xf1,    (uint8_t)~0xff,    (uint8_t)~0xff,    (uint8_t)~0x00,};const uint8_t gr_mask[9] = {    (uint8_t)~0xf0, /* 0x00 */    (uint8_t)~0xf0, /* 0x01 */    (uint8_t)~0xf0, /* 0x02 */    (uint8_t)~0xe0, /* 0x03 */    (uint8_t)~0xfc, /* 0x04 */    (uint8_t)~0x84, /* 0x05 */    (uint8_t)~0xf0, /* 0x06 */    (uint8_t)~0xf0, /* 0x07 */    (uint8_t)~0x00, /* 0x08 */};static uint8_t *vram_getb(struct hvm_hw_stdvga *s, unsigned int a){    struct page_info *pg = s->vram_page[(a >> 12) & 0x3f];    uint8_t *p = map_domain_page(page_to_mfn(pg));    return &p[a & 0xfff];}static uint32_t *vram_getl(struct hvm_hw_stdvga *s, unsigned int a){    struct page_info *pg = s->vram_page[(a >> 10) & 0x3f];    uint32_t *p = map_domain_page(page_to_mfn(pg));    return &p[a & 0x3ff];}static void vram_put(struct hvm_hw_stdvga *s, void *p){    unmap_domain_page(p);}static int stdvga_outb(uint64_t addr, uint8_t val){    struct hvm_hw_stdvga *s = &current->domain->arch.hvm_domain.stdvga;    int rc = 1, prev_stdvga = s->stdvga;    switch ( addr )    {    case 0x3c4:                 /* sequencer address register */        s->sr_index = val;        break;    case 0x3c5:                 /* sequencer data register */        rc = (s->sr_index < sizeof(s->sr));        if ( rc )            s->sr[s->sr_index] = val & sr_mask[s->sr_index] ;        break;    case 0x3ce:                 /* graphics address register */        s->gr_index = val;        break;    case 0x3cf:                 /* graphics data register */        rc = (s->gr_index < sizeof(s->gr));        if ( rc )            s->gr[s->gr_index] = val & gr_mask[s->gr_index];        break;    default:        rc = 0;        break;    }    /* When in standard vga mode, emulate here all writes to the vram buffer     * so we can immediately satisfy reads without waiting for qemu. */    s->stdvga = (s->sr[7] == 0x00);    if ( !prev_stdvga && s->stdvga )    {        /*         * (Re)start caching of video buffer.         * XXX TODO: In case of a restart the cache could be unsynced.         */        s->cache = 1;        gdprintk(XENLOG_INFO, "entering stdvga and caching modes\n");    }    else if ( prev_stdvga && !s->stdvga )    {        gdprintk(XENLOG_INFO, "leaving stdvga\n");    }    return rc;}static void stdvga_out(uint32_t port, uint32_t bytes, uint32_t val){    switch ( bytes )    {    case 1:        stdvga_outb(port, val);        break;    case 2:        stdvga_outb(port + 0, val >> 0);        stdvga_outb(port + 1, val >> 8);        break;    default:        break;    }}static int stdvga_intercept_pio(    int dir, uint32_t port, uint32_t bytes, uint32_t *val){    struct hvm_hw_stdvga *s = &current->domain->arch.hvm_domain.stdvga;    if ( dir == IOREQ_WRITE )    {        spin_lock(&s->lock);        stdvga_out(port, bytes, *val);        spin_unlock(&s->lock);    }    return X86EMUL_UNHANDLEABLE; /* propagate to external ioemu */}static unsigned int stdvga_mem_offset(    struct hvm_hw_stdvga *s, unsigned int mmio_addr){    unsigned int memory_map_mode = (s->gr[6] >> 2) & 3;    unsigned int offset = mmio_addr & 0x1ffff;    switch ( memory_map_mode )    {    case 0:        break;    case 1:        if ( offset >= 0x10000 )            goto fail;        offset += 0; /* assume bank_offset == 0; */        break;    case 2:        offset -= 0x10000;        if ( offset >= 0x8000 )            goto fail;        break;    default:    case 3:        offset -= 0x18000;        if ( offset >= 0x8000 )            goto fail;        break;    }    return offset; fail:    return ~0u;}#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)static uint8_t stdvga_mem_readb(uint64_t addr){    struct hvm_hw_stdvga *s = &current->domain->arch.hvm_domain.stdvga;    int plane;    uint32_t ret, *vram_l;    uint8_t *vram_b;    addr = stdvga_mem_offset(s, addr);    if ( addr == ~0u )        return 0xff;    if ( s->sr[4] & 0x08 )    {        /* chain 4 mode : simplest access */        vram_b = vram_getb(s, addr);        ret = *vram_b;        vram_put(s, vram_b);    }    else if ( s->gr[5] & 0x10 )    {        /* odd/even mode (aka text mode mapping) */        plane = (s->gr[4] & 2) | (addr & 1);        vram_b = vram_getb(s, ((addr & ~1) << 1) | plane);        ret = *vram_b;        vram_put(s, vram_b);    }    else    {        /* standard VGA latched access */        vram_l = vram_getl(s, addr);        s->latch = *vram_l;        vram_put(s, vram_l);        if ( !(s->gr[5] & 0x08) )        {            /* read mode 0 */            plane = s->gr[4];            ret = GET_PLANE(s->latch, plane);        }        else        {            /* read mode 1 */            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];            ret |= ret >> 16;            ret |= ret >> 8;            ret = (~ret) & 0xff;        }    }    return ret;}static uint64_t stdvga_mem_read(uint64_t addr, uint64_t size){    uint64_t data = 0;    switch ( size )    {    case 1:        data = stdvga_mem_readb(addr);        break;    case 2:        data = stdvga_mem_readb(addr);        data |= stdvga_mem_readb(addr + 1) << 8;        break;    case 4:        data = stdvga_mem_readb(addr);        data |= stdvga_mem_readb(addr + 1) << 8;        data |= stdvga_mem_readb(addr + 2) << 16;        data |= stdvga_mem_readb(addr + 3) << 24;        break;    case 8:        data =  (uint64_t)(stdvga_mem_readb(addr));        data |= (uint64_t)(stdvga_mem_readb(addr + 1)) << 8;        data |= (uint64_t)(stdvga_mem_readb(addr + 2)) << 16;        data |= (uint64_t)(stdvga_mem_readb(addr + 3)) << 24;        data |= (uint64_t)(stdvga_mem_readb(addr + 4)) << 32;        data |= (uint64_t)(stdvga_mem_readb(addr + 5)) << 40;        data |= (uint64_t)(stdvga_mem_readb(addr + 6)) << 48;        data |= (uint64_t)(stdvga_mem_readb(addr + 7)) << 56;        break;    default:        gdprintk(XENLOG_WARNING, "invalid io size: %"PRId64"\n", size);        break;    }    return data;}

⌨️ 快捷键说明

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