int vcpu_cell_init(struct cell *cell) { const u8 *pio_bitmap = jailhouse_cell_pio_bitmap(cell->config); u32 pio_bitmap_size = cell->config->pio_bitmap_size; struct vcpu_io_bitmap cell_iobm, root_cell_iobm; unsigned int n, pm_timer_addr; u32 size; int err; u8 *b; /* PM timer has to be provided */ if (system_config->platform_info.x86.pm_timer_address == 0) return -EINVAL; err = vcpu_vendor_cell_init(cell); if (err) { vcpu_cell_exit(cell); return err; } vcpu_vendor_get_cell_io_bitmap(cell, &cell_iobm); memset(cell_iobm.data, -1, cell_iobm.size); for (n = 0; n < 2; n++) { size = pio_bitmap_size <= PAGE_SIZE ? pio_bitmap_size : PAGE_SIZE; memcpy(cell_iobm.data + n * PAGE_SIZE, pio_bitmap, size); pio_bitmap += size; pio_bitmap_size -= size; } /* moderation access to i8042 command register */ cell_iobm.data[I8042_CMD_REG / 8] |= 1 << (I8042_CMD_REG % 8); if (cell != &root_cell) { /* * Shrink PIO access of root cell corresponding to new cell's * access rights. */ vcpu_vendor_get_cell_io_bitmap(&root_cell, &root_cell_iobm); pio_bitmap = jailhouse_cell_pio_bitmap(cell->config); pio_bitmap_size = cell->config->pio_bitmap_size; for (b = root_cell_iobm.data; pio_bitmap_size > 0; b++, pio_bitmap++, pio_bitmap_size--) *b |= ~*pio_bitmap; } /* permit access to the PM timer */ pm_timer_addr = system_config->platform_info.x86.pm_timer_address; for (n = 0; n < 4; n++, pm_timer_addr++) { b = cell_iobm.data; b[pm_timer_addr / 8] &= ~(1 << (pm_timer_addr % 8)); } return 0; }
int i8042_access_handler(u16 port, bool dir_in, unsigned int size) { union registers *guest_regs = &this_cpu_data()->guest_regs; const struct jailhouse_cell_desc *config = this_cell()->config; const u8 *pio_bitmap = jailhouse_cell_pio_bitmap(config); u8 val; if (port == I8042_CMD_REG && config->pio_bitmap_size >= (I8042_CMD_REG + 7) / 8 && !(pio_bitmap[I8042_CMD_REG / 8] & (1 << (I8042_CMD_REG % 8)))) { if (size != 1) goto invalid_access; if (dir_in) { guest_regs->rax &= ~BYTE_MASK(1); guest_regs->rax |= inb(I8042_CMD_REG); } else { val = (u8)guest_regs->rax; if (val == I8042_CMD_WRITE_CTRL_PORT || (val & I8042_CMD_PULSE_CTRL_PORT) == I8042_CMD_PULSE_CTRL_PORT) goto invalid_access; outb(val, I8042_CMD_REG); } return 1; } return 0; invalid_access: panic_printk("FATAL: Invalid write to i8042 controller port\n"); return -1; }
void vcpu_cell_exit(struct cell *cell) { const u8 *root_pio_bitmap = jailhouse_cell_pio_bitmap(root_cell.config); const u8 *pio_bitmap = jailhouse_cell_pio_bitmap(cell->config); u32 pio_bitmap_size = cell->config->pio_bitmap_size; struct vcpu_io_bitmap root_cell_iobm; u8 *b; vcpu_vendor_get_cell_io_bitmap(&root_cell, &root_cell_iobm); if (root_cell.config->pio_bitmap_size < pio_bitmap_size) pio_bitmap_size = root_cell.config->pio_bitmap_size; for (b = root_cell_iobm.data; pio_bitmap_size > 0; b++, pio_bitmap++, root_pio_bitmap++, pio_bitmap_size--) *b &= *pio_bitmap | *root_pio_bitmap; vcpu_vendor_cell_exit(cell); }