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 = ¤t->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 = ¤t->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 = ¤t->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 + -
显示快捷键?