stdvga.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 634 行 · 第 1/2 页
C
634 行
static void stdvga_mem_writeb(uint64_t addr, uint32_t val){ struct hvm_hw_stdvga *s = ¤t->domain->arch.hvm_domain.stdvga; int plane, write_mode, b, func_select, mask; uint32_t write_mask, bit_mask, set_mask, *vram_l; uint8_t *vram_b; addr = stdvga_mem_offset(s, addr); if ( addr == ~0u ) return; if ( s->sr[4] & 0x08 ) { /* chain 4 mode : simplest access */ plane = addr & 3; mask = (1 << plane); if ( s->sr[2] & mask ) { vram_b = vram_getb(s, addr); *vram_b = val; 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); mask = (1 << plane); if ( s->sr[2] & mask ) { addr = ((addr & ~1) << 1) | plane; vram_b = vram_getb(s, addr); *vram_b = val; vram_put(s, vram_b); } } else { write_mode = s->gr[5] & 3; switch ( write_mode ) { default: case 0: /* rotate */ b = s->gr[3] & 7; val = ((val >> b) | (val << (8 - b))) & 0xff; val |= val << 8; val |= val << 16; /* apply set/reset mask */ set_mask = mask16[s->gr[1]]; val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask); bit_mask = s->gr[8]; break; case 1: val = s->latch; goto do_write; case 2: val = mask16[val & 0x0f]; bit_mask = s->gr[8]; break; case 3: /* rotate */ b = s->gr[3] & 7; val = (val >> b) | (val << (8 - b)); bit_mask = s->gr[8] & val; val = mask16[s->gr[0]]; break; } /* apply logical operation */ func_select = s->gr[3] >> 3; switch ( func_select ) { case 0: default: /* nothing to do */ break; case 1: /* and */ val &= s->latch; break; case 2: /* or */ val |= s->latch; break; case 3: /* xor */ val ^= s->latch; break; } /* apply bit mask */ bit_mask |= bit_mask << 8; bit_mask |= bit_mask << 16; val = (val & bit_mask) | (s->latch & ~bit_mask); do_write: /* mask data according to sr[2] */ mask = s->sr[2]; write_mask = mask16[mask]; vram_l = vram_getl(s, addr); *vram_l = (*vram_l & ~write_mask) | (val & write_mask); vram_put(s, vram_l); }}static void stdvga_mem_write(uint64_t addr, uint64_t data, uint64_t size){ /* Intercept mmio write */ switch ( size ) { case 1: stdvga_mem_writeb(addr, (data >> 0) & 0xff); break; case 2: stdvga_mem_writeb(addr+0, (data >> 0) & 0xff); stdvga_mem_writeb(addr+1, (data >> 8) & 0xff); break; case 4: stdvga_mem_writeb(addr+0, (data >> 0) & 0xff); stdvga_mem_writeb(addr+1, (data >> 8) & 0xff); stdvga_mem_writeb(addr+2, (data >> 16) & 0xff); stdvga_mem_writeb(addr+3, (data >> 24) & 0xff); break; case 8: stdvga_mem_writeb(addr+0, (data >> 0) & 0xff); stdvga_mem_writeb(addr+1, (data >> 8) & 0xff); stdvga_mem_writeb(addr+2, (data >> 16) & 0xff); stdvga_mem_writeb(addr+3, (data >> 24) & 0xff); stdvga_mem_writeb(addr+4, (data >> 32) & 0xff); stdvga_mem_writeb(addr+5, (data >> 40) & 0xff); stdvga_mem_writeb(addr+6, (data >> 48) & 0xff); stdvga_mem_writeb(addr+7, (data >> 56) & 0xff); break; default: gdprintk(XENLOG_WARNING, "invalid io size: %"PRId64"\n", size); break; }}static uint32_t read_data;static int mmio_move(struct hvm_hw_stdvga *s, ioreq_t *p){ int i; int sign = p->df ? -1 : 1; p2m_type_t p2mt; if ( p->data_is_ptr ) { if ( p->dir == IOREQ_READ ) { uint64_t addr = p->addr, data = p->data, tmp; for ( i = 0; i < p->count; i++ ) { tmp = stdvga_mem_read(addr, p->size); if ( hvm_copy_to_guest_phys(data, &tmp, p->size) == HVMCOPY_bad_gfn_to_mfn ) { (void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt); /* * The only case we handle is vga_mem <-> vga_mem. * Anything else disables caching and leaves it to qemu-dm. */ if ( (p2mt != p2m_mmio_dm) || (data < VGA_MEM_BASE) || ((data + p->size) > (VGA_MEM_BASE + VGA_MEM_SIZE)) ) return 0; stdvga_mem_write(data, tmp, p->size); } data += sign * p->size; addr += sign * p->size; } } else { uint32_t addr = p->addr, data = p->data, tmp; for ( i = 0; i < p->count; i++ ) { if ( hvm_copy_from_guest_phys(&tmp, data, p->size) == HVMCOPY_bad_gfn_to_mfn ) { (void)gfn_to_mfn_current(data >> PAGE_SHIFT, &p2mt); if ( (p2mt != p2m_mmio_dm) || (data < VGA_MEM_BASE) || ((data + p->size) > (VGA_MEM_BASE + VGA_MEM_SIZE)) ) return 0; tmp = stdvga_mem_read(data, p->size); } stdvga_mem_write(addr, tmp, p->size); data += sign * p->size; addr += sign * p->size; } } } else { if ( p->dir == IOREQ_READ ) { uint32_t addr = p->addr; for ( i = 0; i < p->count; i++ ) { p->data = stdvga_mem_read(addr, p->size); addr += sign * p->size; } } else { uint32_t addr = p->addr; for ( i = 0; i < p->count; i++ ) { stdvga_mem_write(addr, p->data, p->size); addr += sign * p->size; } } } read_data = p->data; return 1;}static int stdvga_intercept_mmio(ioreq_t *p){ struct domain *d = current->domain; struct hvm_hw_stdvga *s = &d->arch.hvm_domain.stdvga; int buf = 0, rc; if ( p->size > 8 ) { gdprintk(XENLOG_WARNING, "invalid mmio size %d\n", (int)p->size); return X86EMUL_UNHANDLEABLE; } spin_lock(&s->lock); if ( s->stdvga && s->cache ) { switch ( p->type ) { case IOREQ_TYPE_COPY: buf = mmio_move(s, p); if ( buf ) break; default: gdprintk(XENLOG_WARNING, "unsupported mmio request type:%d " "addr:0x%04x data:0x%04x size:%d count:%d state:%d " "isptr:%d dir:%d df:%d\n", p->type, (int)p->addr, (int)p->data, (int)p->size, (int)p->count, p->state, p->data_is_ptr, p->dir, p->df); s->cache = 0; } } else { buf = (p->dir == IOREQ_WRITE); } rc = (buf && hvm_buffered_io_send(p)); spin_unlock(&s->lock); return rc ? X86EMUL_OKAY : X86EMUL_UNHANDLEABLE;}void stdvga_init(struct domain *d){ struct hvm_hw_stdvga *s = &d->arch.hvm_domain.stdvga; struct page_info *pg; void *p; int i; memset(s, 0, sizeof(*s)); spin_lock_init(&s->lock); for ( i = 0; i != ARRAY_SIZE(s->vram_page); i++ ) { pg = alloc_domheap_page(NULL, MEMF_node(domain_to_node(d))); if ( pg == NULL ) break; s->vram_page[i] = pg; p = map_domain_page(page_to_mfn(pg)); clear_page(p); unmap_domain_page(p); } if ( i == ARRAY_SIZE(s->vram_page) ) { /* Sequencer registers. */ register_portio_handler(d, 0x3c4, 2, stdvga_intercept_pio); /* Graphics registers. */ register_portio_handler(d, 0x3ce, 2, stdvga_intercept_pio); /* MMIO. */ register_buffered_io_handler( d, VGA_MEM_BASE, VGA_MEM_SIZE, stdvga_intercept_mmio); }}void stdvga_deinit(struct domain *d){ struct hvm_hw_stdvga *s = &d->arch.hvm_domain.stdvga; int i; for ( i = 0; i != ARRAY_SIZE(s->vram_page); i++ ) { if ( s->vram_page[i] == NULL ) continue; free_domheap_page(s->vram_page[i]); s->vram_page[i] = NULL; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?