diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-18 07:34:24 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-03-18 07:34:24 -0500 |
commit | e531761d63b7f8fe6b6423fafb3616ebbff768aa (patch) | |
tree | a4ca2537f1e887d8c81ff6820baccb039634d320 | |
parent | b1999e87b4d42305419329cae459e1b43f706d96 (diff) | |
parent | 1562e53112fd1082c656a06d953a7447ab17e6e1 (diff) | |
download | qemu-e531761d63b7f8fe6b6423fafb3616ebbff768aa.tar.gz qemu-e531761d63b7f8fe6b6423fafb3616ebbff768aa.tar.bz2 qemu-e531761d63b7f8fe6b6423fafb3616ebbff768aa.zip |
Merge remote-tracking branch 'kraxel/pixman.v8' into staging
# By Gerd Hoffmann (18) and others
# Via Blue Swirl (1) and Gerd Hoffmann (1)
* kraxel/pixman.v8: (37 commits)
console: remove ds_get_* helper functions
console: zap color_table
console: stop using DisplayState in gfx hardware emulation
console: zap displaystate from dcl callbacks
cocoa: stop using DisplayState
spice: stop using DisplayState
sdl: stop using DisplayState
vnc: stop using DisplayState
gtk: stop using DisplayState
console: add surface_*() getters
console: rework DisplaySurface handling [dcl/ui side]
console: rework DisplaySurface handling [vga emu side]
sdl: drop dead code
qxl: better vga init in enter_vga_mode
qxl: zap qxl0 global
spice: zap sdpy global
console: kill DisplayState->opaque
console: fix displaychangelisteners interface
s390: Fix cpu refactoring fallout.
target-mips: fix rndrashift_short_acc and code for EXTR_ instructions
...
62 files changed, 3506 insertions, 1198 deletions
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 68b204547c..ab8703578e 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -42,6 +42,7 @@ CONFIG_PL110=y CONFIG_PL181=y CONFIG_PL190=y CONFIG_PL310=y +CONFIG_PL330=y CONFIG_CADENCE=y CONFIG_XGMAC=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index eb7eb31a19..11812c6a4e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -98,6 +98,7 @@ common-obj-$(CONFIG_PL110) += pl110.o common-obj-$(CONFIG_PL181) += pl181.o common-obj-$(CONFIG_PL190) += pl190.o common-obj-$(CONFIG_PL310) += arm_l2x0.o +common-obj-$(CONFIG_PL330) += pl330.o common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_CADENCE) += cadence_uart.o diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index a37dbd7961..edd528255f 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -462,7 +462,7 @@ typedef struct musicpal_lcd_state { uint32_t irqctrl; uint32_t page; uint32_t page_off; - DisplayState *ds; + QemuConsole *con; uint8_t video_ram[128*64/8]; } musicpal_lcd_state; @@ -483,7 +483,8 @@ static inline void glue(set_lcd_pixel, depth) \ (musicpal_lcd_state *s, int x, int y, type col) \ { \ int dx, dy; \ - type *pixel = &((type *) ds_get_data(s->ds))[(y * 128 * 3 + x) * 3]; \ + DisplaySurface *surface = qemu_console_surface(s->con); \ + type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \ \ for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \ for (dx = 0; dx < 3; dx++, pixel++) \ @@ -496,9 +497,10 @@ SET_LCD_PIXEL(32, uint32_t) static void lcd_refresh(void *opaque) { musicpal_lcd_state *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int x, y, col; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; #define LCD_REFRESH(depth, func) \ @@ -518,14 +520,14 @@ static void lcd_refresh(void *opaque) break; LCD_REFRESH(8, rgb_to_pixel8) LCD_REFRESH(16, rgb_to_pixel16) - LCD_REFRESH(32, (is_surface_bgr(s->ds->surface) ? + LCD_REFRESH(32, (is_surface_bgr(surface) ? rgb_to_pixel32bgr : rgb_to_pixel32)) default: hw_error("unsupported colour depth %i\n", - ds_get_bits_per_pixel(s->ds)); + surface_bits_per_pixel(surface)); } - dpy_gfx_update(s->ds, 0, 0, 128*3, 64*3); + dpy_gfx_update(s->con, 0, 0, 128*3, 64*3); } static void lcd_invalidate(void *opaque) @@ -609,9 +611,9 @@ static int musicpal_lcd_init(SysBusDevice *dev) "musicpal-lcd", MP_LCD_SIZE); sysbus_init_mmio(dev, &s->iomem); - s->ds = graphic_console_init(lcd_refresh, lcd_invalidate, - NULL, NULL, s); - qemu_console_resize(s->ds, 128*3, 64*3); + s->con = graphic_console_init(lcd_refresh, lcd_invalidate, + NULL, NULL, s); + qemu_console_resize(s->con, 128*3, 64*3); qdev_init_gpio_in(&dev->qdev, musicpal_lcd_gpio_brigthness_in, 3); diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index c5bf9f95b3..6747c1c547 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -1290,7 +1290,6 @@ static void n8x0_init(QEMUMachineInitArgs *args, MemoryRegion *sysmem = get_system_memory(); struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s)); int sdram_size = binfo->ram_size; - DisplayState *ds; s->mpu = omap2420_mpu_init(sysmem, sdram_size, args->cpu_model); @@ -1370,12 +1369,6 @@ static void n8x0_init(QEMUMachineInitArgs *args, n800_setup_nolo_tags(nolo_tags); cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); } - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds = get_displaystate(); - ds->surface = qemu_resize_displaysurface(ds, 800, 480); - dpy_gfx_resize(ds); } static struct arm_boot_info n800_binfo = { diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 91bc74af24..baeb585067 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -205,7 +205,6 @@ static void palmte_init(QEMUMachineInitArgs *args) static uint32_t cs2val = 0x0000e1a0; static uint32_t cs3val = 0xe1a0e1a0; int rom_size, rom_loaded = 0; - DisplayState *ds = get_displaystate(); MemoryRegion *flash = g_new(MemoryRegion, 1); MemoryRegion *cs = g_new(MemoryRegion, 4); @@ -268,12 +267,6 @@ static void palmte_init(QEMUMachineInitArgs *args) palmte_binfo.initrd_filename = initrd_filename; arm_load_kernel(mpu->cpu, &palmte_binfo); } - - /* FIXME: We shouldn't really be doing this here. The LCD controller - will set the size once configured, so this just sets an initial - size until the guest activates the display. */ - ds->surface = qemu_resize_displaysurface(ds, 320, 320); - dpy_gfx_resize(ds); } static QEMUMachine palmte_machine = { diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 02922c38b3..2e1a5d0e5b 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -147,19 +147,24 @@ typedef struct VEDBoardInfo VEDBoardInfo; typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id); + qemu_irq *pic); struct VEDBoardInfo { const hwaddr *motherboard_map; hwaddr loader_start; const hwaddr gic_cpu_if_addr; + uint32_t proc_id; + uint32_t num_voltage_sensors; + const uint32_t *voltages; + uint32_t num_clocks; + const uint32_t *clocks; DBoardInitFn *init; }; static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) + qemu_irq *pic) { MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -175,8 +180,6 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_model = "cortex-a9"; } - *proc_id = 0x0c000191; - for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu = cpu_arm_init(cpu_model); if (!cpu) { @@ -247,17 +250,41 @@ static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, sysbus_create_varargs("l2x0", 0x1e00a000, NULL); } +/* Voltage values for SYS_CFG_VOLT daughterboard registers; + * values are in microvolts. + */ +static const uint32_t a9_voltages[] = { + 1000000, /* VD10 : 1.0V : SoC internal logic voltage */ + 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */ + 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */ + 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */ + 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */ + 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ +}; + +/* Reset values for daughterboard oscillators (in Hz) */ +static const uint32_t a9_clocks[] = { + 45000000, /* AMBA AXI ACLK: 45MHz */ + 23750000, /* daughterboard CLCD clock: 23.75MHz */ + 66670000, /* Test chip reference clock: 66.67MHz */ +}; + static const VEDBoardInfo a9_daughterboard = { .motherboard_map = motherboard_legacy_map, .loader_start = 0x60000000, .gic_cpu_if_addr = 0x1e000100, + .proc_id = 0x0c000191, + .num_voltage_sensors = ARRAY_SIZE(a9_voltages), + .voltages = a9_voltages, + .num_clocks = ARRAY_SIZE(a9_clocks), + .clocks = a9_clocks, .init = a9_daughterboard_init, }; static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, ram_addr_t ram_size, const char *cpu_model, - qemu_irq *pic, uint32_t *proc_id) + qemu_irq *pic) { int n; MemoryRegion *sysmem = get_system_memory(); @@ -271,8 +298,6 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, cpu_model = "cortex-a15"; } - *proc_id = 0x14000237; - for (n = 0; n < smp_cpus; n++) { ARMCPU *cpu; qemu_irq *irqp; @@ -340,10 +365,31 @@ static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, /* 0x7ffd0000: PL354 static memory controller: not modelled */ } +static const uint32_t a15_voltages[] = { + 900000, /* Vcore: 0.9V : CPU core voltage */ +}; + +static const uint32_t a15_clocks[] = { + 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */ + 0, /* OSCCLK1: reserved */ + 0, /* OSCCLK2: reserved */ + 0, /* OSCCLK3: reserved */ + 40000000, /* OSCCLK4: 40MHz : external AXI master clock */ + 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */ + 50000000, /* OSCCLK6: 50MHz : static memory controller clock */ + 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */ + 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */ +}; + static const VEDBoardInfo a15_daughterboard = { .motherboard_map = motherboard_aseries_map, .loader_start = 0x80000000, .gic_cpu_if_addr = 0x2c002000, + .proc_id = 0x14000237, + .num_voltage_sensors = ARRAY_SIZE(a15_voltages), + .voltages = a15_voltages, + .num_clocks = ARRAY_SIZE(a15_clocks), + .clocks = a15_clocks, .init = a15_daughterboard_init, }; @@ -352,7 +398,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, { DeviceState *dev, *sysctl, *pl041; qemu_irq pic[64]; - uint32_t proc_id; uint32_t sys_id; DriveInfo *dinfo; ram_addr_t vram_size, sram_size; @@ -360,9 +405,9 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, MemoryRegion *vram = g_new(MemoryRegion, 1); MemoryRegion *sram = g_new(MemoryRegion, 1); const hwaddr *map = daughterboard->motherboard_map; + int i; - daughterboard->init(daughterboard, args->ram_size, args->cpu_model, - pic, &proc_id); + daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); /* Motherboard peripherals: the wiring is the same but the * addresses vary between the legacy and A-Series memory maps. @@ -372,7 +417,21 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, sysctl = qdev_create(NULL, "realview_sysctl"); qdev_prop_set_uint32(sysctl, "sys_id", sys_id); - qdev_prop_set_uint32(sysctl, "proc_id", proc_id); + qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); + qdev_prop_set_uint32(sysctl, "len-db-voltage", + daughterboard->num_voltage_sensors); + for (i = 0; i < daughterboard->num_voltage_sensors; i++) { + char *propname = g_strdup_printf("db-voltage[%d]", i); + qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); + g_free(propname); + } + qdev_prop_set_uint32(sysctl, "len-db-clock", + daughterboard->num_clocks); + for (i = 0; i < daughterboard->num_clocks; i++) { + char *propname = g_strdup_printf("db-clock[%d]", i); + qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); + g_free(propname); + } qdev_init_nofail(sysctl); sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index f78c47e43e..6f362865f9 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -35,6 +35,10 @@ #define IRQ_OFFSET 32 /* pic interrupts start from index 32 */ +static const int dma_irqs[8] = { + 46, 47, 48, 49, 72, 73, 74, 75 +}; + static struct arm_boot_info zynq_binfo = {}; static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) @@ -196,6 +200,26 @@ static void zynq_init(QEMUMachineInitArgs *args) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); + dev = qdev_create(NULL, "pl330"); + qdev_prop_set_uint8(dev, "num_chnls", 8); + qdev_prop_set_uint8(dev, "num_periph_req", 4); + qdev_prop_set_uint8(dev, "num_events", 16); + + qdev_prop_set_uint8(dev, "data_width", 64); + qdev_prop_set_uint8(dev, "wr_cap", 8); + qdev_prop_set_uint8(dev, "wr_q_dep", 16); + qdev_prop_set_uint8(dev, "rd_cap", 8); + qdev_prop_set_uint8(dev, "rd_q_dep", 16); + qdev_prop_set_uint16(dev, "data_buffer_dep", 256); + + qdev_init_nofail(dev); + busdev = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(busdev, 0, 0xF8003000); + sysbus_connect_irq(busdev, 0, pic[45-IRQ_OFFSET]); /* abort irq line */ + for (n = 0; n < 8; ++n) { /* event irqs */ + sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); + } + zynq_binfo.ram_size = ram_size; zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_cmdline = kernel_cmdline; diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index a46f8d450e..25fc6eac94 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -9,6 +9,7 @@ #include "hw/hw.h" #include "qemu/timer.h" +#include "qemu/bitops.h" #include "hw/sysbus.h" #include "hw/primecell.h" #include "sysemu/sysemu.h" @@ -34,11 +35,17 @@ typedef struct { uint32_t sys_cfgctrl; uint32_t sys_cfgstat; uint32_t sys_clcd; + uint32_t mb_clock[6]; + uint32_t *db_clock; + uint32_t db_num_vsensors; + uint32_t *db_voltage; + uint32_t db_num_clocks; + uint32_t *db_clock_reset; } arm_sysctl_state; static const VMStateDescription vmstate_arm_sysctl = { .name = "realview_sysctl", - .version_id = 3, + .version_id = 4, .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT32(leds, arm_sysctl_state), @@ -53,6 +60,9 @@ static const VMStateDescription vmstate_arm_sysctl = { VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2), VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2), VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3), + VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4), + VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks, + 4, vmstate_info_uint32, uint32_t), VMSTATE_END_OF_LIST() } }; @@ -76,6 +86,7 @@ static int board_id(arm_sysctl_state *s) static void arm_sysctl_reset(DeviceState *d) { arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + int i; s->leds = 0; s->lockval = 0; @@ -83,6 +94,17 @@ static void arm_sysctl_reset(DeviceState *d) s->cfgdata2 = 0; s->flags = 0; s->resetlevel = 0; + /* Motherboard oscillators (in Hz) */ + s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */ + s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */ + s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */ + s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */ + s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */ + s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */ + /* Daughterboard oscillators: reset from property values */ + for (i = 0; i < s->db_num_clocks; i++) { + s->db_clock[i] = s->db_clock_reset[i]; + } if (board_id(s) == BOARD_ID_VEXPRESS) { /* On VExpress this register will RAZ/WI */ s->sys_clcd = 0; @@ -191,6 +213,166 @@ static uint64_t arm_sysctl_read(void *opaque, hwaddr offset, } } +/* SYS_CFGCTRL functions */ +#define SYS_CFG_OSC 1 +#define SYS_CFG_VOLT 2 +#define SYS_CFG_AMP 3 +#define SYS_CFG_TEMP 4 +#define SYS_CFG_RESET 5 +#define SYS_CFG_SCC 6 +#define SYS_CFG_MUXFPGA 7 +#define SYS_CFG_SHUTDOWN 8 +#define SYS_CFG_REBOOT 9 +#define SYS_CFG_DVIMODE 11 +#define SYS_CFG_POWER 12 +#define SYS_CFG_ENERGY 13 + +/* SYS_CFGCTRL site field values */ +#define SYS_CFG_SITE_MB 0 +#define SYS_CFG_SITE_DB1 1 +#define SYS_CFG_SITE_DB2 2 + +/** + * vexpress_cfgctrl_read: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: pointer to where to put the read data on success + * + * Handle a VExpress SYS_CFGCTRL register read. On success, return true and + * write the read value to *val. On failure, return false (and val may + * or may not be written to). + */ +static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t *val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + case SYS_CFG_VOLT: + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) { + *val = s->db_voltage[device]; + return true; + } + if (site == SYS_CFG_SITE_MB && device == 0) { + /* There is only one motherboard voltage sensor: + * VIO : 3.3V : bus voltage between mother and daughterboard + */ + *val = 3300000; + return true; + } + break; + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + *val = s->mb_clock[device]; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + *val = s->db_clock[device]; + return true; + } + break; + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL read of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + +/** + * vexpress_cfgctrl_write: + * @s: arm_sysctl_state pointer + * @dcc, @function, @site, @position, @device: split out values from + * SYS_CFGCTRL register + * @val: data to write + * + * Handle a VExpress SYS_CFGCTRL register write. On success, return true. + * On failure, return false. + */ +static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc, + unsigned int function, unsigned int site, + unsigned int position, unsigned int device, + uint32_t val) +{ + /* We don't support anything other than DCC 0, board stack position 0 + * or sites other than motherboard/daughterboard: + */ + if (dcc != 0 || position != 0 || + (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) { + goto cfgctrl_unimp; + } + + switch (function) { + case SYS_CFG_OSC: + if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) { + /* motherboard clock */ + s->mb_clock[device] = val; + return true; + } + if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) { + /* daughterboard clock */ + s->db_clock[device] = val; + return true; + } + break; + case SYS_CFG_MUXFPGA: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Select whether video output comes from motherboard + * or daughterboard: log and ignore as QEMU doesn't + * support this. + */ + qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output " + "not supported, ignoring\n"); + return true; + } + break; + case SYS_CFG_SHUTDOWN: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_shutdown_request(); + return true; + } + break; + case SYS_CFG_REBOOT: + if (site == SYS_CFG_SITE_MB && device == 0) { + qemu_system_reset_request(); + return true; + } + break; + case SYS_CFG_DVIMODE: + if (site == SYS_CFG_SITE_MB && device == 0) { + /* Selecting DVI mode is meaningless for QEMU: we will + * always display the output correctly according to the + * pixel height/width programmed into the CLCD controller. + */ + return true; + } + default: + break; + } + +cfgctrl_unimp: + qemu_log_mask(LOG_UNIMP, + "arm_sysctl: Unimplemented SYS_CFGCTRL write of function " + "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n", + function, dcc, site, position, device); + return false; +} + static void arm_sysctl_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { @@ -322,17 +504,33 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, if (board_id(s) != BOARD_ID_VEXPRESS) { goto bad_reg; } - s->sys_cfgctrl = val & ~(3 << 18); - s->sys_cfgstat = 1; /* complete */ - switch (s->sys_cfgctrl) { - case 0xc0800000: /* SYS_CFG_SHUTDOWN to motherboard */ - qemu_system_shutdown_request(); - break; - case 0xc0900000: /* SYS_CFG_REBOOT to motherboard */ - qemu_system_reset_request(); - break; - default: - s->sys_cfgstat |= 2; /* error */ + /* Undefined bits [19:18] are RAZ/WI, and writing to + * the start bit just triggers the action; it always reads + * as zero. + */ + s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31)); + if (val & (1 << 31)) { + /* Start bit set -- actually do something */ + unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4); + unsigned int function = extract32(s->sys_cfgctrl, 20, 6); + unsigned int site = extract32(s->sys_cfgctrl, 16, 2); + unsigned int position = extract32(s->sys_cfgctrl, 12, 4); + unsigned int device = extract32(s->sys_cfgctrl, 0, 12); + s->sys_cfgstat = 1; /* complete */ + if (s->sys_cfgctrl & (1 << 30)) { + if (!vexpress_cfgctrl_write(s, dcc, function, site, position, + device, s->sys_cfgdata)) { + s->sys_cfgstat |= 2; /* error */ + } + } else { + uint32_t val; + if (!vexpress_cfgctrl_read(s, dcc, function, site, position, + device, &val)) { + s->sys_cfgstat |= 2; /* error */ + } else { + s->sys_cfgdata = val; + } + } } s->sys_cfgctrl &= ~(1 << 31); return; @@ -385,29 +583,50 @@ static void arm_sysctl_gpio_set(void *opaque, int line, int level) } } -static int arm_sysctl_init(SysBusDevice *dev) +static void arm_sysctl_init(Object *obj) { - arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + DeviceState *dev = DEVICE(obj); + SysBusDevice *sd = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd); memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2); - qdev_init_gpio_out(&s->busdev.qdev, &s->pl110_mux_ctrl, 1); - return 0; + sysbus_init_mmio(sd, &s->iomem); + qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2); + qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1); +} + +static void arm_sysctl_realize(DeviceState *d, Error **errp) +{ + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d)); + s->db_clock = g_new0(uint32_t, s->db_num_clocks); +} + +static void arm_sysctl_finalize(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev); + g_free(s->db_voltage); + g_free(s->db_clock); + g_free(s->db_clock_reset); } static Property arm_sysctl_properties[] = { DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), + /* Daughterboard power supply voltages (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors, + db_voltage, qdev_prop_uint32, uint32_t), + /* Daughterboard clock reset values (as reported via SYS_CFG) */ + DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks, + db_clock_reset, qdev_prop_uint32, uint32_t), DEFINE_PROP_END_OF_LIST(), }; static void arm_sysctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = arm_sysctl_init; + dc->realize = arm_sysctl_realize; dc->reset = arm_sysctl_reset; dc->vmsd = &vmstate_arm_sysctl; dc->props = arm_sysctl_properties; @@ -417,6 +636,8 @@ static const TypeInfo arm_sysctl_info = { .name = "realview_sysctl", .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(arm_sysctl_state), + .instance_init = arm_sysctl_init, + .instance_finalize = arm_sysctl_finalize, .class_init = arm_sysctl_class_init, }; diff --git a/hw/blizzard.c b/hw/blizzard.c index 805f4d5558..020d3de431 100644 --- a/hw/blizzard.c +++ b/hw/blizzard.c @@ -69,7 +69,7 @@ typedef struct { uint8_t effect; uint8_t iformat; uint8_t source; - DisplayState *state; + QemuConsole *con; blizzard_fn_t *line_fn_tab[2]; void *fb; @@ -144,6 +144,7 @@ static inline void blizzard_rgb2yuv(int r, int g, int b, static void blizzard_window(BlizzardState *s) { + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *src, *dst; int bypp[2]; int bypl[3]; @@ -162,7 +163,7 @@ static void blizzard_window(BlizzardState *s) s->my[1] = s->data.y + s->data.dy; bypp[0] = s->bpp; - bypp[1] = (ds_get_bits_per_pixel(s->state) + 7) >> 3; + bypp[1] = surface_bytes_per_pixel(surface); bypl[0] = bypp[0] * s->data.pitch; bypl[1] = bypp[1] * s->x; bypl[2] = bypp[0] * s->data.dx; @@ -883,23 +884,25 @@ void s1d13745_write_block(void *opaque, int dc, static void blizzard_update_display(void *opaque) { BlizzardState *s = (BlizzardState *) opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int y, bypp, bypl, bwidth; uint8_t *src, *dst; if (!s->enable) return; - if (s->x != ds_get_width(s->state) || s->y != ds_get_height(s->state)) { + if (s->x != surface_width(surface) || s->y != surface_height(surface)) { s->invalidate = 1; - qemu_console_resize(s->state, s->x, s->y); + qemu_console_resize(s->con, s->x, s->y); + surface = qemu_console_surface(s->con); } if (s->invalidate) { s->invalidate = 0; if (s->blank) { - bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3; - memset(ds_get_data(s->state), 0, bypp * s->x * s->y); + bypp = surface_bytes_per_pixel(surface); + memset(surface_data(surface), 0, bypp * s->x * s->y); return; } @@ -912,16 +915,16 @@ static void blizzard_update_display(void *opaque) if (s->mx[1] <= s->mx[0]) return; - bypp = (ds_get_bits_per_pixel(s->state) + 7) >> 3; + bypp = surface_bytes_per_pixel(surface); bypl = bypp * s->x; bwidth = bypp * (s->mx[1] - s->mx[0]); y = s->my[0]; src = s->fb + bypl * y + bypp * s->mx[0]; - dst = ds_get_data(s->state) + bypl * y + bypp * s->mx[0]; + dst = surface_data(surface) + bypl * y + bypp * s->mx[0]; for (; y < s->my[1]; y ++, src += bypl, dst += bypl) memcpy(dst, src, bwidth); - dpy_gfx_update(s->state, s->mx[0], s->my[0], + dpy_gfx_update(s->con, s->mx[0], s->my[0], s->mx[1] - s->mx[0], y - s->my[0]); s->mx[0] = s->x; @@ -934,10 +937,12 @@ static void blizzard_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { BlizzardState *s = (BlizzardState *) opaque; + DisplaySurface *surface = qemu_console_surface(s->con); blizzard_update_display(opaque); - if (s && ds_get_data(s->state)) - ppm_save(filename, s->state->surface, errp); + if (s && surface_data(surface)) { + ppm_save(filename, surface, errp); + } } #define DEPTH 8 @@ -954,14 +959,16 @@ static void blizzard_screen_dump(void *opaque, const char *filename, void *s1d13745_init(qemu_irq gpio_int) { BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s)); + DisplaySurface *surface; s->fb = g_malloc(0x180000); - s->state = graphic_console_init(blizzard_update_display, - blizzard_invalidate_display, - blizzard_screen_dump, NULL, s); + s->con = graphic_console_init(blizzard_update_display, + blizzard_invalidate_display, + blizzard_screen_dump, NULL, s); + surface = qemu_console_surface(s->con); - switch (ds_get_bits_per_pixel(s->state)) { + switch (surface_bits_per_pixel(surface)) { case 0: s->line_fn_tab[0] = s->line_fn_tab[1] = g_malloc0(sizeof(blizzard_fn_t) * 0x10); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 7babcb67c8..7a4d63436e 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -729,11 +729,12 @@ static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, s->cirrus_blt_width, s->cirrus_blt_height); - if (notify) - qemu_console_copy(s->vga.ds, + if (notify) { + qemu_console_copy(s->vga.con, sx, sy, dx, dy, s->cirrus_blt_width / depth, s->cirrus_blt_height); + } /* we don't have to notify the display that this portion has changed since qemu_console_copy implies this */ @@ -2176,6 +2177,7 @@ static void cirrus_cursor_invalidate(VGACommonState *s1) static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) { CirrusVGAState *s = container_of(s1, CirrusVGAState, vga); + DisplaySurface *surface = qemu_console_surface(s->vga.con); int w, h, bpp, x1, x2, poffset; unsigned int color0, color1; const uint8_t *palette, *src; @@ -2228,9 +2230,9 @@ static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) color1 = s->vga.rgb_to_pixel(c6_to_8(palette[0xf * 3]), c6_to_8(palette[0xf * 3 + 1]), c6_to_8(palette[0xf * 3 + 2])); - bpp = ((ds_get_bits_per_pixel(s->vga.ds) + 7) >> 3); + bpp = surface_bytes_per_pixel(surface); d1 += x1 * bpp; - switch(ds_get_bits_per_pixel(s->vga.ds)) { + switch (surface_bits_per_pixel(surface)) { default: break; case 8: @@ -2908,9 +2910,9 @@ static int vga_initfn(ISADevice *dev) vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, isa_address_space(dev), isa_address_space_io(dev)); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, - s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, + s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ @@ -2957,9 +2959,9 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) vga_common_init(&s->vga); cirrus_init_common(s, device_id, 1, pci_address_space(dev), pci_address_space_io(dev)); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - &s->vga); + s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, + s->vga.screen_dump, s->vga.text_update, + &s->vga); /* setup PCI */ diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c index 6b31ae33b6..bf316c62ab 100644 --- a/hw/exynos4210_fimd.c +++ b/hw/exynos4210_fimd.c @@ -296,7 +296,7 @@ struct Exynos4210fimdWindow { typedef struct { SysBusDevice busdev; MemoryRegion iomem; - DisplayState *console; + QemuConsole *console; qemu_irq irq[3]; uint32_t vidcon[4]; /* Video main control registers 0-3 */ @@ -1221,16 +1221,18 @@ static void exynos4210_fimd_invalidate(void *opaque) static void exynos4210_update_resolution(Exynos4210fimdState *s) { + DisplaySurface *surface = qemu_console_surface(s->console); + /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */ uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; - if (s->ifb == NULL || ds_get_width(s->console) != width || - ds_get_height(s->console) != height) { + if (s->ifb == NULL || surface_width(surface) != width || + surface_height(surface) != height) { DPRINT_L1("Resolution changed from %ux%u to %ux%u\n", - ds_get_width(s->console), ds_get_height(s->console), width, height); + surface_width(surface), surface_height(surface), width, height); qemu_console_resize(s->console, width, height); s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1); memset(s->ifb, 0, width * height * RGBA_SIZE + 1); @@ -1241,6 +1243,7 @@ static void exynos4210_update_resolution(Exynos4210fimdState *s) static void exynos4210_fimd_update(void *opaque) { Exynos4210fimdState *s = (Exynos4210fimdState *)opaque; + DisplaySurface *surface = qemu_console_surface(s->console); Exynos4210fimdWindow *w; int i, line; hwaddr fb_line_addr, inc_size; @@ -1253,7 +1256,7 @@ static void exynos4210_fimd_update(void *opaque) const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) & FIMD_VIDTCON2_SIZE_MASK) + 1; - if (!s || !s->console || !ds_get_bits_per_pixel(s->console) || + if (!s || !s->console || !surface_bits_per_pixel(surface) || !s->enabled) { return; } @@ -1299,10 +1302,10 @@ static void exynos4210_fimd_update(void *opaque) uint8_t *d; int bpp; - bpp = ds_get_bits_per_pixel(s->console); + bpp = surface_bits_per_pixel(surface); fimd_update_putpix_qemu(bpp); bpp = (bpp + 1) >> 3; - d = ds_get_data(s->console); + d = surface_data(surface); for (line = first_line; line <= last_line; line++) { fimd_copy_line_toqemu(global_width, s->ifb + global_width * line * RGBA_SIZE, d + global_width * line * bpp); diff --git a/hw/framebuffer.c b/hw/framebuffer.c index d341aa0c6b..7326a98a41 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -24,7 +24,7 @@ /* Render an image from a shared memory framebuffer. */ void framebuffer_update_display( - DisplayState *ds, + DisplaySurface *ds, MemoryRegion *address_space, hwaddr base, int cols, /* Width in pixels. */ @@ -73,7 +73,7 @@ void framebuffer_update_display( return; } src = src_base; - dest = ds_get_data(ds); + dest = surface_data(ds); if (dest_col_pitch < 0) dest -= dest_col_pitch * (cols - 1); if (dest_row_pitch < 0) { diff --git a/hw/framebuffer.h b/hw/framebuffer.h index 11f53edec0..6eae035b7d 100644 --- a/hw/framebuffer.h +++ b/hw/framebuffer.h @@ -8,7 +8,7 @@ typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int); void framebuffer_update_display( - DisplayState *ds, + DisplaySurface *ds, MemoryRegion *address_space, hwaddr base, int cols, diff --git a/hw/g364fb.c b/hw/g364fb.c index 7b69815bc9..f7014e9dd8 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -39,7 +39,7 @@ typedef struct G364State { uint32_t top_of_screen; uint32_t width, height; /* in pixels */ /* display refresh support */ - DisplayState *ds; + QemuConsole *con; int depth; int blanked; } G364State; @@ -77,6 +77,7 @@ static inline void reset_dirty(G364State *s, static void g364fb_draw_graphic8(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *vram; uint8_t *data_display, *dd; @@ -87,7 +88,7 @@ static void g364fb_draw_graphic8(G364State *s) int xcursor, ycursor; unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b); - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: rgb_to_pixel = rgb_to_pixel8; w = 1; @@ -106,7 +107,7 @@ static void g364fb_draw_graphic8(G364State *s) break; default: hw_error("g364: unknown host depth %d", - ds_get_bits_per_pixel(s->ds)); + surface_bits_per_pixel(surface)); return; } @@ -129,7 +130,7 @@ static void g364fb_draw_graphic8(G364State *s) vram = s->vram + s->top_of_screen; /* XXX: out of range in vram? */ - data_display = dd = ds_get_data(s->ds); + data_display = dd = surface_data(surface); while (y < s->height) { if (check_dirty(s, page)) { if (y < ymin) @@ -182,7 +183,7 @@ static void g364fb_draw_graphic8(G364State *s) ymax = s->height - 1; goto done; } - data_display = dd = data_display + ds_get_linesize(s->ds); + data_display = dd = data_display + surface_stride(surface); xmin = 0; x = 0; } @@ -197,7 +198,7 @@ static void g364fb_draw_graphic8(G364State *s) reset_dirty(s, page_min, page_max); page_min = (ram_addr_t)-1; page_max = 0; - dpy_gfx_update(s->ds, xmin, ymin, + dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); xmin = s->width; xmax = 0; @@ -209,7 +210,7 @@ static void g364fb_draw_graphic8(G364State *s) x = x % s->width; y += dy; vram += G364_PAGE_SIZE; - data_display += dy * ds_get_linesize(s->ds); + data_display += dy * surface_stride(surface); dd = data_display + x * w; } page += G364_PAGE_SIZE; @@ -217,13 +218,14 @@ static void g364fb_draw_graphic8(G364State *s) done: if (page_min != (ram_addr_t)-1) { - dpy_gfx_update(s->ds, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); + dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); reset_dirty(s, page_min, page_max); } } static void g364fb_draw_blank(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *d; @@ -232,28 +234,30 @@ static void g364fb_draw_blank(G364State *s) return; } - w = s->width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + w = s->width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for (i = 0; i < s->height; i++) { memset(d, 0, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, s->width, s->height); + dpy_gfx_update(s->con, 0, 0, s->width, s->height); s->blanked = 1; } static void g364fb_update_display(void *opaque) { G364State *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); qemu_flush_coalesced_mmio_buffer(); if (s->width == 0 || s->height == 0) return; - if (s->width != ds_get_width(s->ds) || s->height != ds_get_height(s->ds)) { - qemu_console_resize(s->ds, s->width, s->height); + if (s->width != surface_width(surface) || + s->height != surface_height(surface)) { + qemu_console_resize(s->con, s->width, s->height); } if (s->ctla & CTLA_FORCE_BLANK) { @@ -413,13 +417,14 @@ static void g364fb_update_depth(G364State *s) static void g364_invalidate_cursor_position(G364State *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int ymin, ymax, start, end; /* invalidate only near the cursor */ ymin = s->cursor_position & 0xfff; ymax = MIN(s->height, ymin + 64); - start = ymin * ds_get_linesize(s->ds); - end = (ymax + 1) * ds_get_linesize(s->ds); + start = ymin * surface_stride(surface); + end = (ymax + 1) * surface_stride(surface); memory_region_set_dirty(&s->mem_vram, start, end - start); } @@ -545,9 +550,9 @@ static void g364fb_init(DeviceState *dev, G364State *s) { s->vram = g_malloc0(s->vram_size); - s->ds = graphic_console_init(g364fb_update_display, - g364fb_invalidate_display, - g364fb_screen_dump, NULL, s); + s->con = graphic_console_init(g364fb_update_display, + g364fb_invalidate_display, + g364fb_screen_dump, NULL, s); memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000); memory_region_init_ram_ptr(&s->mem_vram, "vram", diff --git a/hw/jazz_led.c b/hw/jazz_led.c index a418a7d1b6..05528c7c81 100644 --- a/hw/jazz_led.c +++ b/hw/jazz_led.c @@ -36,7 +36,7 @@ typedef struct LedState { SysBusDevice busdev; MemoryRegion iomem; uint8_t segments; - DisplayState *ds; + QemuConsole *con; screen_state_t state; } LedState; @@ -75,13 +75,15 @@ static const MemoryRegionOps led_ops = { /***********************************************************/ /* jazz_led display */ -static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color) +static void draw_horizontal_line(DisplaySurface *ds, + int posy, int posx1, int posx2, + uint32_t color) { uint8_t *d; int x, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d = ds_get_data(ds) + ds_get_linesize(ds) * posy + bpp * posx1; + bpp = (surface_bits_per_pixel(ds) + 7) >> 3; + d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1; switch(bpp) { case 1: for (x = posx1; x <= posx2; x++) { @@ -104,30 +106,32 @@ static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx } } -static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color) +static void draw_vertical_line(DisplaySurface *ds, + int posx, int posy1, int posy2, + uint32_t color) { uint8_t *d; int y, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d = ds_get_data(ds) + ds_get_linesize(ds) * posy1 + bpp * posx; + bpp = (surface_bits_per_pixel(ds) + 7) >> 3; + d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx; switch(bpp) { case 1: for (y = posy1; y <= posy2; y++) { *((uint8_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; case 2: for (y = posy1; y <= posy2; y++) { *((uint16_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; case 4: for (y = posy1; y <= posy2; y++) { *((uint32_t *)d) = color; - d += ds_get_linesize(ds); + d += surface_stride(ds); } break; } @@ -136,24 +140,24 @@ static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, static void jazz_led_update_display(void *opaque) { LedState *s = opaque; - DisplayState *ds = s->ds; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *d1; uint32_t color_segment, color_led; int y, bpp; if (s->state & REDRAW_BACKGROUND) { /* clear screen */ - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d1 = ds_get_data(ds); - for (y = 0; y < ds_get_height(ds); y++) { - memset(d1, 0x00, ds_get_width(ds) * bpp); - d1 += ds_get_linesize(ds); + bpp = (surface_bits_per_pixel(surface) + 7) >> 3; + d1 = surface_data(surface); + for (y = 0; y < surface_height(surface); y++) { + memset(d1, 0x00, surface_width(surface) * bpp); + d1 += surface_stride(surface); } } if (s->state & REDRAW_SEGMENTS) { /* set colors according to bpp */ - switch (ds_get_bits_per_pixel(ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa); color_led = rgb_to_pixel8(0x00, 0xff, 0x00); @@ -178,26 +182,34 @@ static void jazz_led_update_display(void *opaque) } /* display segments */ - draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0); - draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0); - draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0); - draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0); - draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0); - draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0); - draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0); + draw_horizontal_line(surface, 40, 10, 40, + (s->segments & 0x02) ? color_segment : 0); + draw_vertical_line(surface, 10, 10, 40, + (s->segments & 0x04) ? color_segment : 0); + draw_vertical_line(surface, 10, 40, 70, + (s->segments & 0x08) ? color_segment : 0); + draw_horizontal_line(surface, 70, 10, 40, + (s->segments & 0x10) ? color_segment : 0); + draw_vertical_line(surface, 40, 40, 70, + (s->segments & 0x20) ? color_segment : 0); + draw_vertical_line(surface, 40, 10, 40, + (s->segments & 0x40) ? color_segment : 0); + draw_horizontal_line(surface, 10, 10, 40, + (s->segments & 0x80) ? color_segment : 0); /* display led */ if (!(s->segments & 0x01)) color_led = 0; /* black */ - draw_horizontal_line(ds, 68, 50, 50, color_led); - draw_horizontal_line(ds, 69, 49, 51, color_led); - draw_horizontal_line(ds, 70, 48, 52, color_led); - draw_horizontal_line(ds, 71, 49, 51, color_led); - draw_horizontal_line(ds, 72, 50, 50, color_led); + draw_horizontal_line(surface, 68, 50, 50, color_led); + draw_horizontal_line(surface, 69, 49, 51, color_led); + draw_horizontal_line(surface, 70, 48, 52, color_led); + draw_horizontal_line(surface, 71, 49, 51, color_led); + draw_horizontal_line(surface, 72, 50, 50, color_led); } s->state = REDRAW_NONE; - dpy_gfx_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); + dpy_gfx_update(s->con, 0, 0, + surface_width(surface), surface_height(surface)); } static void jazz_led_invalidate_display(void *opaque) @@ -211,15 +223,15 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata) LedState *s = opaque; char buf[2]; - dpy_text_cursor(s->ds, -1, -1); - qemu_console_resize(s->ds, 2, 1); + dpy_text_cursor(s->con, -1, -1); + qemu_console_resize(s->con, 2, 1); /* TODO: draw the segments */ snprintf(buf, 2, "%02hhx\n", s->segments); console_write_ch(chardata++, 0x00200100 | buf[0]); console_write_ch(chardata++, 0x00200100 | buf[1]); - dpy_text_update(s->ds, 0, 0, 2, 1); + dpy_text_update(s->con, 0, 0, 2, 1); } static int jazz_led_post_load(void *opaque, int version_id) @@ -249,10 +261,10 @@ static int jazz_led_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); - s->ds = graphic_console_init(jazz_led_update_display, - jazz_led_invalidate_display, - NULL, - jazz_led_text_update, s); + s->con = graphic_console_init(jazz_led_update_display, + jazz_led_invalidate_display, + NULL, + jazz_led_text_update, s); return 0; } @@ -263,7 +275,7 @@ static void jazz_led_reset(DeviceState *d) s->segments = 0; s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND; - qemu_console_resize(s->ds, 60, 80); + qemu_console_resize(s->con, 60, 80); } static void jazz_led_class_init(ObjectClass *klass, void *data) diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 85ebb851bd..98762ecd21 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -66,7 +66,7 @@ enum { struct MilkymistVgafbState { SysBusDevice busdev; MemoryRegion regs_region; - DisplayState *ds; + QemuConsole *con; int invalidate; uint32_t fb_offset; @@ -84,6 +84,7 @@ static int vgafb_enabled(MilkymistVgafbState *s) static void vgafb_update_display(void *opaque) { MilkymistVgafbState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int first = 0; int last = 0; drawfn fn; @@ -94,7 +95,7 @@ static void vgafb_update_display(void *opaque) int dest_width = s->regs[R_HRES]; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 8: @@ -121,7 +122,7 @@ static void vgafb_update_display(void *opaque) break; } - framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(&s->busdev), s->regs[R_BASEADDRESS] + s->fb_offset, s->regs[R_HRES], s->regs[R_VRES], @@ -134,7 +135,7 @@ static void vgafb_update_display(void *opaque) &first, &last); if (first >= 0) { - dpy_gfx_update(s->ds, 0, first, s->regs[R_HRES], last - first + 1); + dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1); } s->invalidate = 0; } @@ -151,7 +152,7 @@ static void vgafb_resize(MilkymistVgafbState *s) return; } - qemu_console_resize(s->ds, s->regs[R_HRES], s->regs[R_VRES]); + qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]); s->invalidate = 1; } @@ -277,9 +278,9 @@ static int milkymist_vgafb_init(SysBusDevice *dev) "milkymist-vgafb", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); - s->ds = graphic_console_init(vgafb_update_display, - vgafb_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(vgafb_update_display, + vgafb_invalidate_display, + NULL, NULL, s); return 0; } diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c index c426f3a13a..4f5b0947cf 100644 --- a/hw/omap_lcdc.c +++ b/hw/omap_lcdc.c @@ -26,7 +26,7 @@ struct omap_lcd_panel_s { MemoryRegion *sysmem; MemoryRegion iomem; qemu_irq irq; - DisplayState *state; + QemuConsole *con; int plm; int tft; @@ -113,14 +113,16 @@ static draw_line_func draw_line_table2[33] = { static void omap_update_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; + DisplaySurface *surface = qemu_console_surface(omap_lcd->con); draw_line_func draw_line; int size, height, first, last; int width, linesize, step, bpp, frame_offset; hwaddr frame_base; - if (!omap_lcd || omap_lcd->plm == 1 || - !omap_lcd->enable || !ds_get_bits_per_pixel(omap_lcd->state)) + if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || + !surface_bits_per_pixel(surface)) { return; + } frame_offset = 0; if (omap_lcd->plm != 2) { @@ -139,25 +141,25 @@ static void omap_update_display(void *opaque) /* Colour depth */ switch ((omap_lcd->palette[0] >> 12) & 7) { case 1: - draw_line = draw_line_table2[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table2[surface_bits_per_pixel(surface)]; bpp = 2; break; case 2: - draw_line = draw_line_table4[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table4[surface_bits_per_pixel(surface)]; bpp = 4; break; case 3: - draw_line = draw_line_table8[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table8[surface_bits_per_pixel(surface)]; bpp = 8; break; case 4 ... 7: if (!omap_lcd->tft) - draw_line = draw_line_table12[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table12[surface_bits_per_pixel(surface)]; else - draw_line = draw_line_table16[ds_get_bits_per_pixel(omap_lcd->state)]; + draw_line = draw_line_table16[surface_bits_per_pixel(surface)]; bpp = 16; break; @@ -168,10 +170,11 @@ static void omap_update_display(void *opaque) /* Resolution */ width = omap_lcd->width; - if (width != ds_get_width(omap_lcd->state) || - omap_lcd->height != ds_get_height(omap_lcd->state)) { - qemu_console_resize(omap_lcd->state, + if (width != surface_width(surface) || + omap_lcd->height != surface_height(surface)) { + qemu_console_resize(omap_lcd->con, omap_lcd->width, omap_lcd->height); + surface = qemu_console_surface(omap_lcd->con); omap_lcd->invalidate = 1; } @@ -196,8 +199,9 @@ static void omap_update_display(void *opaque) if (omap_lcd->dma->dual) omap_lcd->dma->current_frame ^= 1; - if (!ds_get_bits_per_pixel(omap_lcd->state)) + if (!surface_bits_per_pixel(surface)) { return; + } first = 0; height = omap_lcd->height; @@ -210,15 +214,15 @@ static void omap_update_display(void *opaque) } step = width * bpp >> 3; - linesize = ds_get_linesize(omap_lcd->state); - framebuffer_update_display(omap_lcd->state, omap_lcd->sysmem, + linesize = surface_stride(surface); + framebuffer_update_display(surface, omap_lcd->sysmem, frame_base, width, height, step, linesize, 0, omap_lcd->invalidate, draw_line, omap_lcd->palette, &first, &last); if (first >= 0) { - dpy_gfx_update(omap_lcd->state, 0, first, width, last - first + 1); + dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1); } omap_lcd->invalidate = 0; } @@ -298,12 +302,13 @@ static void omap_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { struct omap_lcd_panel_s *omap_lcd = opaque; + DisplaySurface *surface = qemu_console_surface(omap_lcd->con); omap_update_display(opaque); - if (omap_lcd && ds_get_data(omap_lcd->state)) - omap_ppm_save(filename, ds_get_data(omap_lcd->state), + if (omap_lcd && surface_data(surface)) + omap_ppm_save(filename, surface_data(surface), omap_lcd->width, omap_lcd->height, - ds_get_linesize(omap_lcd->state), errp); + surface_stride(surface), errp); } static void omap_invalidate_display(void *opaque) { @@ -480,9 +485,9 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100); memory_region_add_subregion(sysmem, base, &s->iomem); - s->state = graphic_console_init(omap_update_display, - omap_invalidate_display, - omap_screen_dump, NULL, s); + s->con = graphic_console_init(omap_update_display, + omap_invalidate_display, + omap_screen_dump, NULL, s); return s; } diff --git a/hw/pl110.c b/hw/pl110.c index 924642d697..fbef675f9c 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -42,7 +42,7 @@ enum pl110_version typedef struct { SysBusDevice busdev; MemoryRegion iomem; - DisplayState *ds; + QemuConsole *con; int version; uint32_t timing[4]; @@ -129,6 +129,7 @@ static int pl110_enabled(pl110_state *s) static void pl110_update_display(void *opaque) { pl110_state *s = (pl110_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); drawfn* fntable; drawfn fn; int dest_width; @@ -140,7 +141,7 @@ static void pl110_update_display(void *opaque) if (!pl110_enabled(s)) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 8: @@ -231,14 +232,14 @@ static void pl110_update_display(void *opaque) } dest_width *= s->cols; first = 0; - framebuffer_update_display(s->ds, sysbus_address_space(&s->busdev), + framebuffer_update_display(surface, sysbus_address_space(&s->busdev), s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, fn, s->palette, &first, &last); if (first >= 0) { - dpy_gfx_update(s->ds, 0, first, s->cols, last - first + 1); + dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1); } s->invalidate = 0; } @@ -248,12 +249,13 @@ static void pl110_invalidate_display(void * opaque) pl110_state *s = (pl110_state *)opaque; s->invalidate = 1; if (pl110_enabled(s)) { - qemu_console_resize(s->ds, s->cols, s->rows); + qemu_console_resize(s->con, s->cols, s->rows); } } static void pl110_update_palette(pl110_state *s, int n) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; uint32_t raw; unsigned int r, g, b; @@ -268,7 +270,7 @@ static void pl110_update_palette(pl110_state *s, int n) b = (raw & 0x1f) << 3; /* The I bit is ignored. */ raw >>= 6; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: s->palette[n] = rgb_to_pixel8(r, g, b); break; @@ -291,7 +293,7 @@ static void pl110_resize(pl110_state *s, int width, int height) { if (width != s->cols || height != s->rows) { if (pl110_enabled(s)) { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); } } s->cols = width; @@ -409,7 +411,7 @@ static void pl110_write(void *opaque, hwaddr offset, s->cr = val; s->bpp = (val >> 1) & 7; if (pl110_enabled(s)) { - qemu_console_resize(s->ds, s->cols, s->rows); + qemu_console_resize(s->con, s->cols, s->rows); } break; case 10: /* LCDICR */ @@ -450,9 +452,9 @@ static int pl110_init(SysBusDevice *dev) sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1); - s->ds = graphic_console_init(pl110_update_display, - pl110_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(pl110_update_display, + pl110_invalidate_display, + NULL, NULL, s); return 0; } diff --git a/hw/pl330.c b/hw/pl330.c new file mode 100644 index 0000000000..1a04773a71 --- /dev/null +++ b/hw/pl330.c @@ -0,0 +1,1654 @@ +/* + * ARM PrimeCell PL330 DMA Controller + * + * Copyright (c) 2009 Samsung Electronics. + * Contributed by Kirill Batuzov <batuzovk@ispras.ru> + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 or later. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "sysbus.h" +#include "qemu/timer.h" +#include "sysemu/dma.h" + +#ifndef PL330_ERR_DEBUG +#define PL330_ERR_DEBUG 0 +#endif + +#define DB_PRINT_L(lvl, fmt, args...) do {\ + if (PL330_ERR_DEBUG >= lvl) {\ + fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\ + } \ +} while (0); + +#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args) + +#define PL330_PERIPH_NUM 32 +#define PL330_MAX_BURST_LEN 128 +#define PL330_INSN_MAXSIZE 6 + +#define PL330_FIFO_OK 0 +#define PL330_FIFO_STALL 1 +#define PL330_FIFO_ERR (-1) + +#define PL330_FAULT_UNDEF_INSTR (1 << 0) +#define PL330_FAULT_OPERAND_INVALID (1 << 1) +#define PL330_FAULT_DMAGO_ERR (1 << 4) +#define PL330_FAULT_EVENT_ERR (1 << 5) +#define PL330_FAULT_CH_PERIPH_ERR (1 << 6) +#define PL330_FAULT_CH_RDWR_ERR (1 << 7) +#define PL330_FAULT_ST_DATA_UNAVAILABLE (1 << 12) +#define PL330_FAULT_FIFOEMPTY_ERR (1 << 13) +#define PL330_FAULT_INSTR_FETCH_ERR (1 << 16) +#define PL330_FAULT_DATA_WRITE_ERR (1 << 17) +#define PL330_FAULT_DATA_READ_ERR (1 << 18) +#define PL330_FAULT_DBG_INSTR (1 << 30) +#define PL330_FAULT_LOCKUP_ERR (1 << 31) + +#define PL330_UNTAGGED 0xff + +#define PL330_SINGLE 0x0 +#define PL330_BURST 0x1 + +#define PL330_WATCHDOG_LIMIT 1024 + +/* IOMEM mapped registers */ +#define PL330_REG_DSR 0x000 +#define PL330_REG_DPC 0x004 +#define PL330_REG_INTEN 0x020 +#define PL330_REG_INT_EVENT_RIS 0x024 +#define PL330_REG_INTMIS 0x028 +#define PL330_REG_INTCLR 0x02C +#define PL330_REG_FSRD 0x030 +#define PL330_REG_FSRC 0x034 +#define PL330_REG_FTRD 0x038 +#define PL330_REG_FTR_BASE 0x040 +#define PL330_REG_CSR_BASE 0x100 +#define PL330_REG_CPC_BASE 0x104 +#define PL330_REG_CHANCTRL 0x400 +#define PL330_REG_DBGSTATUS 0xD00 +#define PL330_REG_DBGCMD 0xD04 +#define PL330_REG_DBGINST0 0xD08 +#define PL330_REG_DBGINST1 0xD0C +#define PL330_REG_CR0_BASE 0xE00 +#define PL330_REG_PERIPH_ID 0xFE0 + +#define PL330_IOMEM_SIZE 0x1000 + +#define CFG_BOOT_ADDR 2 +#define CFG_INS 3 +#define CFG_PNS 4 +#define CFG_CRD 5 + +static const uint32_t pl330_id[] = { + 0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1 +}; + +/* DMA channel states as they are described in PL330 Technical Reference Manual + * Most of them will not be used in emulation. + */ +typedef enum { + pl330_chan_stopped = 0, + pl330_chan_executing = 1, + pl330_chan_cache_miss = 2, + pl330_chan_updating_pc = 3, + pl330_chan_waiting_event = 4, + pl330_chan_at_barrier = 5, + pl330_chan_queue_busy = 6, + pl330_chan_waiting_periph = 7, + pl330_chan_killing = 8, + pl330_chan_completing = 9, + pl330_chan_fault_completing = 14, + pl330_chan_fault = 15, +} PL330ChanState; + +typedef struct PL330State PL330State; + +typedef struct PL330Chan { + uint32_t src; + uint32_t dst; + uint32_t pc; + uint32_t control; + uint32_t status; + uint32_t lc[2]; + uint32_t fault_type; + uint32_t watchdog_timer; + + bool ns; + uint8_t request_flag; + uint8_t wakeup; + uint8_t wfp_sbp; + + uint8_t state; + uint8_t stall; + + bool is_manager; + PL330State *parent; + uint8_t tag; +} PL330Chan; + +static const VMStateDescription vmstate_pl330_chan = { + .name = "pl330_chan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(src, PL330Chan), + VMSTATE_UINT32(dst, PL330Chan), + VMSTATE_UINT32(pc, PL330Chan), + VMSTATE_UINT32(control, PL330Chan), + VMSTATE_UINT32(status, PL330Chan), + VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2), + VMSTATE_UINT32(fault_type, PL330Chan), + VMSTATE_UINT32(watchdog_timer, PL330Chan), + VMSTATE_BOOL(ns, PL330Chan), + VMSTATE_UINT8(request_flag, PL330Chan), + VMSTATE_UINT8(wakeup, PL330Chan), + VMSTATE_UINT8(wfp_sbp, PL330Chan), + VMSTATE_UINT8(state, PL330Chan), + VMSTATE_UINT8(stall, PL330Chan), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330Fifo { + uint8_t *buf; + uint8_t *tag; + uint32_t head; + uint32_t num; + uint32_t buf_size; +} PL330Fifo; + +static const VMStateDescription vmstate_pl330_fifo = { + .name = "pl330_chan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size), + VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size), + VMSTATE_UINT32(head, PL330Fifo), + VMSTATE_UINT32(num, PL330Fifo), + VMSTATE_UINT32(buf_size, PL330Fifo), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330QueueEntry { + uint32_t addr; + uint32_t len; + uint8_t n; + bool inc; + bool z; + uint8_t tag; + uint8_t seqn; +} PL330QueueEntry; + +static const VMStateDescription vmstate_pl330_queue_entry = { + .name = "pl330_queue_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(addr, PL330QueueEntry), + VMSTATE_UINT32(len, PL330QueueEntry), + VMSTATE_UINT8(n, PL330QueueEntry), + VMSTATE_BOOL(inc, PL330QueueEntry), + VMSTATE_BOOL(z, PL330QueueEntry), + VMSTATE_UINT8(tag, PL330QueueEntry), + VMSTATE_UINT8(seqn, PL330QueueEntry), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330Queue { + PL330State *parent; + PL330QueueEntry *queue; + uint32_t queue_size; +} PL330Queue; + +static const VMStateDescription vmstate_pl330_queue = { + .name = "pl330_queue", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1, + vmstate_pl330_queue_entry, PL330QueueEntry), + VMSTATE_END_OF_LIST() + } +}; + +struct PL330State { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq_abort; + qemu_irq *irq; + + /* Config registers. cfg[5] = CfgDn. */ + uint32_t cfg[6]; +#define EVENT_SEC_STATE 3 +#define PERIPH_SEC_STATE 4 + /* cfg 0 bits and pieces */ + uint32_t num_chnls; + uint8_t num_periph_req; + uint8_t num_events; + uint8_t mgr_ns_at_rst; + /* cfg 1 bits and pieces */ + uint8_t i_cache_len; + uint8_t num_i_cache_lines; + /* CRD bits and pieces */ + uint8_t data_width; + uint8_t wr_cap; + uint8_t wr_q_dep; + uint8_t rd_cap; + uint8_t rd_q_dep; + uint16_t data_buffer_dep; + + PL330Chan manager; + PL330Chan *chan; + PL330Fifo fifo; + PL330Queue read_queue; + PL330Queue write_queue; + uint8_t *lo_seqn; + uint8_t *hi_seqn; + QEMUTimer *timer; /* is used for restore dma. */ + + uint32_t inten; + uint32_t int_status; + uint32_t ev_status; + uint32_t dbg[2]; + uint8_t debug_status; + uint8_t num_faulting; + uint8_t periph_busy[PL330_PERIPH_NUM]; + +}; + +#define TYPE_PL330 "pl330" +#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330) + +static const VMStateDescription vmstate_pl330 = { + .name = "pl330", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan), + VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0, + vmstate_pl330_chan, PL330Chan), + VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls), + VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls), + VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo), + VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue, + PL330Queue), + VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue, + PL330Queue), + VMSTATE_TIMER(timer, PL330State), + VMSTATE_UINT32(inten, PL330State), + VMSTATE_UINT32(int_status, PL330State), + VMSTATE_UINT32(ev_status, PL330State), + VMSTATE_UINT32_ARRAY(dbg, PL330State, 2), + VMSTATE_UINT8(debug_status, PL330State), + VMSTATE_UINT8(num_faulting, PL330State), + VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM), + VMSTATE_END_OF_LIST() + } +}; + +typedef struct PL330InsnDesc { + /* OPCODE of the instruction */ + uint8_t opcode; + /* Mask so we can select several sibling instructions, such as + DMALD, DMALDS and DMALDB */ + uint8_t opmask; + /* Size of instruction in bytes */ + uint8_t size; + /* Interpreter */ + void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len); +} PL330InsnDesc; + + +/* MFIFO Implementation + * + * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are + * stored in this buffer. Data is stored in BUF field, tags - in the + * corresponding array elements of TAG field. + */ + +/* Initialize queue. */ + +static void pl330_fifo_init(PL330Fifo *s, uint32_t size) +{ + s->buf = g_malloc0(size); + s->tag = g_malloc0(size); + s->buf_size = size; +} + +/* Cyclic increment */ + +static inline int pl330_fifo_inc(PL330Fifo *s, int x) +{ + return (x + 1) % s->buf_size; +} + +/* Number of empty bytes in MFIFO */ + +static inline int pl330_fifo_num_free(PL330Fifo *s) +{ + return s->buf_size - s->num; +} + +/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG. + * Zero returned on success, PL330_FIFO_STALL if there is no enough free + * space in MFIFO to store requested amount of data. If push was unsuccessful + * no data is stored to MFIFO. + */ + +static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag) +{ + int i; + + if (s->buf_size - s->num < len) { + return PL330_FIFO_STALL; + } + for (i = 0; i < len; i++) { + int push_idx = (s->head + s->num + i) % s->buf_size; + s->buf[push_idx] = buf[i]; + s->tag[push_idx] = tag; + } + s->num += len; + return PL330_FIFO_OK; +} + +/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each + * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch + * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was + * unsuccessful no data is removed from MFIFO. + */ + +static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag) +{ + int i; + + if (s->num < len) { + return PL330_FIFO_STALL; + } + for (i = 0; i < len; i++) { + if (s->tag[s->head] == tag) { + int get_idx = (s->head + i) % s->buf_size; + buf[i] = s->buf[get_idx]; + } else { /* Tag mismatch - Rollback transaction */ + return PL330_FIFO_ERR; + } + } + s->head = (s->head + len) % s->buf_size; + s->num -= len; + return PL330_FIFO_OK; +} + +/* Reset MFIFO. This completely erases all data in it. */ + +static inline void pl330_fifo_reset(PL330Fifo *s) +{ + s->head = 0; + s->num = 0; +} + +/* Return tag of the first byte stored in MFIFO. If MFIFO is empty + * PL330_UNTAGGED is returned. + */ + +static inline uint8_t pl330_fifo_tag(PL330Fifo *s) +{ + return (!s->num) ? PL330_UNTAGGED : s->tag[s->head]; +} + +/* Returns non-zero if tag TAG is present in fifo or zero otherwise */ + +static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag) +{ + int i, n; + + i = s->head; + for (n = 0; n < s->num; n++) { + if (s->tag[i] == tag) { + return 1; + } + i = pl330_fifo_inc(s, i); + } + return 0; +} + +/* Remove all entry tagged with TAG from MFIFO */ + +static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag) +{ + int i, t, n; + + t = i = s->head; + for (n = 0; n < s->num; n++) { + if (s->tag[i] != tag) { + s->buf[t] = s->buf[i]; + s->tag[t] = s->tag[i]; + t = pl330_fifo_inc(s, t); + } else { + s->num = s->num - 1; + } + i = pl330_fifo_inc(s, i); + } +} + +/* Read-Write Queue implementation + * + * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores). + * Each instruction is described by source (for loads) or destination (for + * stores) address ADDR, width of data to be loaded/stored LEN, number of + * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel + * this instruction belongs to. Queue does not store any information about + * nature of the instruction: is it load or store. PL330 has different queues + * for loads and stores so this is already known at the top level where it + * matters. + * + * Queue works as FIFO for instructions with equivalent tags, but can issue + * instructions with different tags in arbitrary order. SEQN field attached to + * each instruction helps to achieve this. For each TAG queue contains + * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to + * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is + * followed by SEQN=0. + * + * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed + * in this case. + */ + +static void pl330_queue_reset(PL330Queue *s) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + s->queue[i].tag = PL330_UNTAGGED; + } +} + +/* Initialize queue */ +static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent) +{ + s->parent = parent; + s->queue = g_new0(PL330QueueEntry, size); + s->queue_size = size; +} + +/* Returns pointer to an empty slot or NULL if queue is full */ +static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag == PL330_UNTAGGED) { + return &s->queue[i]; + } + } + return NULL; +} + +/* Put instruction in queue. + * Return value: + * - zero - OK + * - non-zero - queue is full + */ + +static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr, + int len, int n, bool inc, bool z, uint8_t tag) +{ + PL330QueueEntry *entry = pl330_queue_find_empty(s); + + if (!entry) { + return 1; + } + entry->tag = tag; + entry->addr = addr; + entry->len = len; + entry->n = n; + entry->z = z; + entry->inc = inc; + entry->seqn = s->parent->hi_seqn[tag]; + s->parent->hi_seqn[tag]++; + return 0; +} + +/* Returns a pointer to queue slot containing instruction which satisfies + * following conditions: + * - it has valid tag value (not PL330_UNTAGGED) + * - if enforce_seq is set it has to be issuable without violating queue + * logic (see above) + * - if TAG argument is not PL330_UNTAGGED this instruction has tag value + * equivalent to the argument TAG value. + * If such instruction cannot be found NULL is returned. + */ + +static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag, + bool enforce_seq) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag != PL330_UNTAGGED) { + if ((!enforce_seq || + s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) && + (s->queue[i].tag == tag || tag == PL330_UNTAGGED || + s->queue[i].z)) { + return &s->queue[i]; + } + } + } + return NULL; +} + +/* Removes instruction from queue. */ + +static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e) +{ + s->parent->lo_seqn[e->tag]++; + e->tag = PL330_UNTAGGED; +} + +/* Removes all instructions tagged with TAG from queue. */ + +static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag) +{ + int i; + + for (i = 0; i < s->queue_size; i++) { + if (s->queue[i].tag == tag) { + s->queue[i].tag = PL330_UNTAGGED; + } + } +} + +/* DMA instruction execution engine */ + +/* Moves DMA channel to the FAULT state and updates it's status. */ + +static inline void pl330_fault(PL330Chan *ch, uint32_t flags) +{ + DB_PRINT("ch: %p, flags: %x\n", ch, flags); + ch->fault_type |= flags; + if (ch->state == pl330_chan_fault) { + return; + } + ch->state = pl330_chan_fault; + ch->parent->num_faulting++; + if (ch->parent->num_faulting == 1) { + DB_PRINT("abort interrupt raised\n"); + qemu_irq_raise(ch->parent->irq_abort); + } +} + +/* + * For information about instructions see PL330 Technical Reference Manual. + * + * Arguments: + * CH - channel executing the instruction + * OPCODE - opcode + * ARGS - array of 8-bit arguments + * LEN - number of elements in ARGS array + */ + +static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]); + uint8_t ra = (opcode >> 1) & 1; + + if (ch->is_manager) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return; + } + if (ra) { + ch->dst += im; + } else { + ch->src += im; + } +} + +static void pl330_dmaend(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + PL330State *s = ch->parent; + + if (ch->state == pl330_chan_executing && !ch->is_manager) { + /* Wait for all transfers to complete */ + if (pl330_fifo_has_tag(&s->fifo, ch->tag) || + pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL || + pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) { + + ch->stall = 1; + return; + } + } + DB_PRINT("DMA ending!\n"); + pl330_fifo_tagged_remove(&s->fifo, ch->tag); + pl330_queue_remove_tagged(&s->read_queue, ch->tag); + pl330_queue_remove_tagged(&s->write_queue, ch->tag); + ch->state = pl330_chan_stopped; +} + +static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + /* Do nothing */ +} + +static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t chan_id; + uint8_t ns; + uint32_t pc; + PL330Chan *s; + + DB_PRINT("\n"); + + if (!ch->is_manager) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return; + } + ns = !!(opcode & 2); + chan_id = args[0] & 7; + if ((args[0] >> 3)) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (chan_id >= ch->parent->num_chnls) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) | + (((uint32_t)args[2]) << 8) | (((uint32_t)args[1])); + if (ch->parent->chan[chan_id].state != pl330_chan_stopped) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !ns) { + pl330_fault(ch, PL330_FAULT_DMAGO_ERR); + return; + } + s = &ch->parent->chan[chan_id]; + s->ns = ns; + s->pc = pc; + s->state = pl330_chan_executing; +} + +static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint32_t size, num; + bool inc; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + if (bs == 1 && ch->request_flag == PL330_SINGLE) { + num = 1; + } else { + num = ((ch->control >> 4) & 0xf) + 1; + } + size = (uint32_t)1 << ((ch->control >> 1) & 0x7); + inc = !!(ch->control & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src, + size, num, inc, 0, ch->tag); + if (!ch->stall) { + DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + ch->tag, ch->src, size, num, inc ? 'Y' : 'N'); + ch->src += inc ? size * num - (ch->src & (size - 1)) : 0; + } +} + +static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + pl330_dmald(ch, opcode, args, len); +} + +static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t lc = (opcode & 2) >> 1; + + ch->lc[lc] = args[0]; +} + +static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + if (ch->state == pl330_chan_fault || + ch->state == pl330_chan_fault_completing) { + /* This is the only way for a channel to leave the faulting state */ + ch->fault_type = 0; + ch->parent->num_faulting--; + if (ch->parent->num_faulting == 0) { + DB_PRINT("abort interrupt lowered\n"); + qemu_irq_lower(ch->parent->irq_abort); + } + } + ch->state = pl330_chan_killing; + pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag); + pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag); + pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag); + ch->state = pl330_chan_stopped; +} + +static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t nf = (opcode & 0x10) >> 4; + uint8_t bs = opcode & 3; + uint8_t lc = (opcode & 4) >> 2; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + if (!nf || ch->lc[lc]) { + if (nf) { + ch->lc[lc]--; + } + DB_PRINT("loop reiteration\n"); + ch->pc -= args[0]; + ch->pc -= len + 1; + /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */ + } else { + DB_PRINT("loop fallthrough\n"); + } +} + + +static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t rd = args[0] & 7; + uint32_t im; + + if ((args[0] >> 3)) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) | + (((uint32_t)args[2]) << 8) | (((uint32_t)args[1])); + switch (rd) { + case 0: + ch->src = im; + break; + case 1: + ch->control = im; + break; + case 2: + ch->dst = im; + break; + default: + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } +} + +static void pl330_dmanop(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + /* NOP is NOP. */ +} + +static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) { + ch->state = pl330_chan_at_barrier; + ch->stall = 1; + return; + } else { + ch->state = pl330_chan_executing; + } +} + +static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t ev_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + ev_id = (args[0] >> 3) & 0x1f; + if (ev_id >= ch->parent->num_events) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { + pl330_fault(ch, PL330_FAULT_EVENT_ERR); + return; + } + if (ch->parent->inten & (1 << ev_id)) { + ch->parent->int_status |= (1 << ev_id); + DB_PRINT("event interrupt raised %d\n", ev_id); + qemu_irq_raise(ch->parent->irq[ev_id]); + } else { + ch->parent->ev_status |= (1 << ev_id); + } +} + +static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint32_t size, num; + bool inc; + + if (bs == 2) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if ((bs == 1 && ch->request_flag == PL330_BURST) || + (bs == 3 && ch->request_flag == PL330_SINGLE)) { + /* Perform NOP */ + return; + } + num = ((ch->control >> 18) & 0xf) + 1; + size = (uint32_t)1 << ((ch->control >> 15) & 0x7); + inc = !!((ch->control >> 14) & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, + size, num, inc, 0, ch->tag); + if (!ch->stall) { + DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n", + ch->tag, ch->dst, size, num, inc ? 'Y' : 'N'); + ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0; + } +} + +static void pl330_dmastp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + pl330_dmast(ch, opcode, args, len); +} + +static void pl330_dmastz(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint32_t size, num; + bool inc; + + num = ((ch->control >> 18) & 0xf) + 1; + size = (uint32_t)1 << ((ch->control >> 15) & 0x7); + inc = !!((ch->control >> 14) & 1); + ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst, + size, num, inc, 1, ch->tag); + if (inc) { + ch->dst += size * num; + } +} + +static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t ev_id; + int i; + + if (args[0] & 5) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + ev_id = (args[0] >> 3) & 0x1f; + if (ev_id >= ch->parent->num_events) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) { + pl330_fault(ch, PL330_FAULT_EVENT_ERR); + return; + } + ch->wakeup = ev_id; + ch->state = pl330_chan_waiting_event; + if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) { + ch->state = pl330_chan_executing; + /* If anyone else is currently waiting on the same event, let them + * clear the ev_status so they pick up event as well + */ + for (i = 0; i < ch->parent->num_chnls; ++i) { + PL330Chan *peer = &ch->parent->chan[i]; + if (peer->state == pl330_chan_waiting_event && + peer->wakeup == ev_id) { + return; + } + } + ch->parent->ev_status &= ~(1 << ev_id); + } else { + ch->stall = 1; + } +} + +static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + uint8_t bs = opcode & 3; + uint8_t periph_id; + + if (args[0] & 7) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + periph_id = (args[0] >> 3) & 0x1f; + if (periph_id >= ch->parent->num_periph_req) { + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) { + pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR); + return; + } + switch (bs) { + case 0: /* S */ + ch->request_flag = PL330_SINGLE; + ch->wfp_sbp = 0; + break; + case 1: /* P */ + ch->request_flag = PL330_BURST; + ch->wfp_sbp = 2; + break; + case 2: /* B */ + ch->request_flag = PL330_BURST; + ch->wfp_sbp = 1; + break; + default: + pl330_fault(ch, PL330_FAULT_OPERAND_INVALID); + return; + } + + if (ch->parent->periph_busy[periph_id]) { + ch->state = pl330_chan_waiting_periph; + ch->stall = 1; + } else if (ch->state == pl330_chan_waiting_periph) { + ch->state = pl330_chan_executing; + } +} + +static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode, + uint8_t *args, int len) +{ + if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) { + ch->state = pl330_chan_at_barrier; + ch->stall = 1; + return; + } else { + ch->state = pl330_chan_executing; + } +} + +/* NULL terminated array of the instruction descriptions. */ +static const PL330InsnDesc insn_desc[] = { + { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, }, + { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, }, + { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, }, + { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, }, + { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, }, + { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, }, + { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, }, + /* dmastp must be before dmalpend in this list, because their maps + * are overlapping + */ + { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, }, + { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, }, + { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, }, + { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, }, + { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, }, + { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, }, + { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, }, + { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, }, + { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, }, + { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, }, + { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, }, + { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, }, + { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, } +}; + +/* Instructions which can be issued via debug registers. */ +static const PL330InsnDesc debug_insn_desc[] = { + { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, }, + { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, }, + { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, }, + { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, } +}; + +static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch) +{ + uint8_t opcode; + int i; + + dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1); + for (i = 0; insn_desc[i].size; i++) { + if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) { + return &insn_desc[i]; + } + } + return NULL; +} + +static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn) +{ + uint8_t buf[PL330_INSN_MAXSIZE]; + + assert(insn->size <= PL330_INSN_MAXSIZE); + dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size); + insn->exec(ch, buf[0], &buf[1], insn->size - 1); +} + +static inline void pl330_update_pc(PL330Chan *ch, + const PL330InsnDesc *insn) +{ + ch->pc += insn->size; +} + +/* Try to execute current instruction in channel CH. Number of executed + instructions is returned (0 or 1). */ +static int pl330_chan_exec(PL330Chan *ch) +{ + const PL330InsnDesc *insn; + + if (ch->state != pl330_chan_executing && + ch->state != pl330_chan_waiting_periph && + ch->state != pl330_chan_at_barrier && + ch->state != pl330_chan_waiting_event) { + DB_PRINT("%d\n", ch->state); + return 0; + } + ch->stall = 0; + insn = pl330_fetch_insn(ch); + if (!insn) { + DB_PRINT("pl330 undefined instruction\n"); + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR); + return 0; + } + pl330_exec_insn(ch, insn); + if (!ch->stall) { + pl330_update_pc(ch, insn); + ch->watchdog_timer = 0; + return 1; + /* WDT only active in exec state */ + } else if (ch->state == pl330_chan_executing) { + ch->watchdog_timer++; + if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) { + pl330_fault(ch, PL330_FAULT_LOCKUP_ERR); + } + } + return 0; +} + +/* Try to execute 1 instruction in each channel, one instruction from read + queue and one instruction from write queue. Number of successfully executed + instructions is returned. */ +static int pl330_exec_cycle(PL330Chan *channel) +{ + PL330State *s = channel->parent; + PL330QueueEntry *q; + int i; + int num_exec = 0; + int fifo_res = 0; + uint8_t buf[PL330_MAX_BURST_LEN]; + + /* Execute one instruction in each channel */ + num_exec += pl330_chan_exec(channel); + + /* Execute one instruction from read queue */ + q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true); + if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) { + int len = q->len - (q->addr & (q->len - 1)); + + dma_memory_read(&dma_context_memory, q->addr, buf, len); + if (PL330_ERR_DEBUG > 1) { + DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", + q->addr, len); + hexdump((char *)buf, stderr, "", len); + } + fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag); + if (fifo_res == PL330_FIFO_OK) { + if (q->inc) { + q->addr += len; + } + q->n--; + if (!q->n) { + pl330_queue_remove_insn(&s->read_queue, q); + } + num_exec++; + } + } + + /* Execute one instruction from write queue. */ + q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true); + if (q != NULL) { + int len = q->len - (q->addr & (q->len - 1)); + + if (q->z) { + for (i = 0; i < len; i++) { + buf[i] = 0; + } + } else { + fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag); + } + if (fifo_res == PL330_FIFO_OK || q->z) { + dma_memory_write(&dma_context_memory, q->addr, buf, len); + if (PL330_ERR_DEBUG > 1) { + DB_PRINT("PL330 read from memory @%08x (size = %08x):\n", + q->addr, len); + hexdump((char *)buf, stderr, "", len); + } + if (q->inc) { + q->addr += len; + } + num_exec++; + } else if (fifo_res == PL330_FIFO_STALL) { + pl330_fault(&channel->parent->chan[q->tag], + PL330_FAULT_FIFOEMPTY_ERR); + } + q->n--; + if (!q->n) { + pl330_queue_remove_insn(&s->write_queue, q); + } + } + + return num_exec; +} + +static int pl330_exec_channel(PL330Chan *channel) +{ + int insr_exec = 0; + + /* TODO: Is it all right to execute everything or should we do per-cycle + simulation? */ + while (pl330_exec_cycle(channel)) { + insr_exec++; + } + + /* Detect deadlock */ + if (channel->state == pl330_chan_executing) { + pl330_fault(channel, PL330_FAULT_LOCKUP_ERR); + } + /* Situation when one of the queues has deadlocked but all channels + * have finished their programs should be impossible. + */ + + return insr_exec; +} + +static inline void pl330_exec(PL330State *s) +{ + DB_PRINT("\n"); + int i, insr_exec; + do { + insr_exec = pl330_exec_channel(&s->manager); + + for (i = 0; i < s->num_chnls; i++) { + insr_exec += pl330_exec_channel(&s->chan[i]); + } + } while (insr_exec); +} + +static void pl330_exec_cycle_timer(void *opaque) +{ + PL330State *s = (PL330State *)opaque; + pl330_exec(s); +} + +/* Stop or restore dma operations */ + +static void pl330_dma_stop_irq(void *opaque, int irq, int level) +{ + PL330State *s = (PL330State *)opaque; + + if (s->periph_busy[irq] != level) { + s->periph_busy[irq] = level; + qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock)); + } +} + +static void pl330_debug_exec(PL330State *s) +{ + uint8_t args[5]; + uint8_t opcode; + uint8_t chan_id; + int i; + PL330Chan *ch; + const PL330InsnDesc *insn; + + s->debug_status = 1; + chan_id = (s->dbg[0] >> 8) & 0x07; + opcode = (s->dbg[0] >> 16) & 0xff; + args[0] = (s->dbg[0] >> 24) & 0xff; + args[1] = (s->dbg[1] >> 0) & 0xff; + args[2] = (s->dbg[1] >> 8) & 0xff; + args[3] = (s->dbg[1] >> 16) & 0xff; + args[4] = (s->dbg[1] >> 24) & 0xff; + DB_PRINT("chan id: %d\n", chan_id); + if (s->dbg[0] & 1) { + ch = &s->chan[chan_id]; + } else { + ch = &s->manager; + } + insn = NULL; + for (i = 0; debug_insn_desc[i].size; i++) { + if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) { + insn = &debug_insn_desc[i]; + } + } + if (!insn) { + pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR); + return ; + } + ch->stall = 0; + insn->exec(ch, opcode, args, insn->size - 1); + if (ch->fault_type) { + ch->fault_type |= PL330_FAULT_DBG_INSTR; + } + if (ch->stall) { + qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not " + "implemented\n"); + } + s->debug_status = 0; +} + +/* IOMEM mapped registers */ + +static void pl330_iomem_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size) +{ + PL330State *s = (PL330State *) opaque; + uint32_t i; + + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value); + + switch (offset) { + case PL330_REG_INTEN: + s->inten = value; + break; + case PL330_REG_INTCLR: + for (i = 0; i < s->num_events; i++) { + if (s->int_status & s->inten & value & (1 << i)) { + DB_PRINT("event interrupt lowered %d\n", i); + qemu_irq_lower(s->irq[i]); + } + } + s->ev_status &= ~(value & s->inten); + s->int_status &= ~(value & s->inten); + break; + case PL330_REG_DBGCMD: + if ((value & 3) == 0) { + pl330_debug_exec(s); + pl330_exec(s); + } else { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u " + "for offset " TARGET_FMT_plx "\n", (unsigned)value, + offset); + } + break; + case PL330_REG_DBGINST0: + DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value); + s->dbg[0] = value; + break; + case PL330_REG_DBGINST1: + DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value); + s->dbg[1] = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx + "\n", offset); + break; + } +} + +static inline uint32_t pl330_iomem_read_imp(void *opaque, + hwaddr offset) +{ + PL330State *s = (PL330State *)opaque; + int chan_id; + int i; + uint32_t res; + + if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) { + return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2]; + } + if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) { + return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2]; + } + if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) { + offset -= PL330_REG_CHANCTRL; + chan_id = offset >> 5; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + switch (offset & 0x1f) { + case 0x00: + return s->chan[chan_id].src; + case 0x04: + return s->chan[chan_id].dst; + case 0x08: + return s->chan[chan_id].control; + case 0x0C: + return s->chan[chan_id].lc[0]; + case 0x10: + return s->chan[chan_id].lc[1]; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + } + if (offset >= PL330_REG_CSR_BASE && offset < 0x400) { + offset -= PL330_REG_CSR_BASE; + chan_id = offset >> 3; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + switch ((offset >> 2) & 1) { + case 0x0: + res = (s->chan[chan_id].ns << 21) | + (s->chan[chan_id].wakeup << 4) | + (s->chan[chan_id].state) | + (s->chan[chan_id].wfp_sbp << 14); + return res; + case 0x1: + return s->chan[chan_id].pc; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n"); + return 0; + } + } + if (offset >= PL330_REG_FTR_BASE && offset < 0x100) { + offset -= PL330_REG_FTR_BASE; + chan_id = offset >> 2; + if (chan_id >= s->num_chnls) { + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + return 0; + } + return s->chan[chan_id].fault_type; + } + switch (offset) { + case PL330_REG_DSR: + return (s->manager.ns << 9) | (s->manager.wakeup << 4) | + (s->manager.state & 0xf); + case PL330_REG_DPC: + return s->manager.pc; + case PL330_REG_INTEN: + return s->inten; + case PL330_REG_INT_EVENT_RIS: + return s->ev_status; + case PL330_REG_INTMIS: + return s->int_status; + case PL330_REG_INTCLR: + /* Documentation says that we can't read this register + * but linux kernel does it + */ + return 0; + case PL330_REG_FSRD: + return s->manager.state ? 1 : 0; + case PL330_REG_FSRC: + res = 0; + for (i = 0; i < s->num_chnls; i++) { + if (s->chan[i].state == pl330_chan_fault || + s->chan[i].state == pl330_chan_fault_completing) { + res |= 1 << i; + } + } + return res; + case PL330_REG_FTRD: + return s->manager.fault_type; + case PL330_REG_DBGSTATUS: + return s->debug_status; + default: + qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset " + TARGET_FMT_plx "\n", offset); + } + return 0; +} + +static uint64_t pl330_iomem_read(void *opaque, hwaddr offset, + unsigned size) +{ + int ret = pl330_iomem_read_imp(opaque, offset); + DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret); + return ret; +} + +static const MemoryRegionOps pl330_ops = { + .read = pl330_iomem_read, + .write = pl330_iomem_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +/* Controller logic and initialization */ + +static void pl330_chan_reset(PL330Chan *ch) +{ + ch->src = 0; + ch->dst = 0; + ch->pc = 0; + ch->state = pl330_chan_stopped; + ch->watchdog_timer = 0; + ch->stall = 0; + ch->control = 0; + ch->status = 0; + ch->fault_type = 0; +} + +static void pl330_reset(DeviceState *d) +{ + int i; + PL330State *s = PL330(d); + + s->inten = 0; + s->int_status = 0; + s->ev_status = 0; + s->debug_status = 0; + s->num_faulting = 0; + s->manager.ns = s->mgr_ns_at_rst; + pl330_fifo_reset(&s->fifo); + pl330_queue_reset(&s->read_queue); + pl330_queue_reset(&s->write_queue); + + for (i = 0; i < s->num_chnls; i++) { + pl330_chan_reset(&s->chan[i]); + } + for (i = 0; i < s->num_periph_req; i++) { + s->periph_busy[i] = 0; + } + + qemu_del_timer(s->timer); +} + +static void pl330_realize(DeviceState *dev, Error **errp) +{ + int i; + PL330State *s = PL330(dev); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort); + memory_region_init_io(&s->iomem, &pl330_ops, s, "dma", PL330_IOMEM_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); + + s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s); + + s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) | + (s->num_periph_req > 0 ? 1 : 0) | + ((s->num_chnls - 1) & 0x7) << 4 | + ((s->num_periph_req - 1) & 0x1f) << 12 | + ((s->num_events - 1) & 0x1f) << 17; + + switch (s->i_cache_len) { + case (4): + s->cfg[1] |= 2; + break; + case (8): + s->cfg[1] |= 3; + break; + case (16): + s->cfg[1] |= 4; + break; + case (32): + s->cfg[1] |= 5; + break; + default: + error_setg(errp, "Bad value for i-cache_len property: %d\n", + s->i_cache_len); + return; + } + s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4; + + s->chan = g_new0(PL330Chan, s->num_chnls); + s->hi_seqn = g_new0(uint8_t, s->num_chnls); + s->lo_seqn = g_new0(uint8_t, s->num_chnls); + for (i = 0; i < s->num_chnls; i++) { + s->chan[i].parent = s; + s->chan[i].tag = (uint8_t)i; + } + s->manager.parent = s; + s->manager.tag = s->num_chnls; + s->manager.is_manager = true; + + s->irq = g_new0(qemu_irq, s->num_events); + for (i = 0; i < s->num_events; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM); + + switch (s->data_width) { + case (32): + s->cfg[CFG_CRD] |= 0x2; + break; + case (64): + s->cfg[CFG_CRD] |= 0x3; + break; + case (128): + s->cfg[CFG_CRD] |= 0x4; + break; + default: + error_setg(errp, "Bad value for data_width property: %d\n", + s->data_width); + return; + } + + s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 | + ((s->wr_q_dep - 1) & 0xf) << 8 | + ((s->rd_cap - 1) & 0x7) << 12 | + ((s->rd_q_dep - 1) & 0xf) << 16 | + ((s->data_buffer_dep - 1) & 0x1ff) << 20; + + pl330_queue_init(&s->read_queue, s->rd_q_dep, s); + pl330_queue_init(&s->write_queue, s->wr_q_dep, s); + pl330_fifo_init(&s->fifo, s->data_buffer_dep); +} + +static Property pl330_properties[] = { + /* CR0 */ + DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8), + DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4), + DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16), + DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0), + /* CR1 */ + DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4), + DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8), + /* CR2-4 */ + DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0), + DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0), + DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0), + /* CRD */ + DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64), + DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8), + DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16), + DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8), + DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16), + DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256), + + DEFINE_PROP_END_OF_LIST(), +}; + +static void pl330_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pl330_realize; + dc->reset = pl330_reset; + dc->props = pl330_properties; + dc->vmsd = &vmstate_pl330; +} + +static const TypeInfo pl330_type_info = { + .name = TYPE_PL330, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PL330State), + .class_init = pl330_class_init, +}; + +static void pl330_register_types(void) +{ + type_register_static(&pl330_type_info); +} + +type_init(pl330_register_types) diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c index 6484d27de1..f2b0c93661 100644 --- a/hw/pxa2xx_lcd.c +++ b/hw/pxa2xx_lcd.c @@ -39,7 +39,7 @@ struct PXA2xxLCDState { int irqlevel; int invalidated; - DisplayState *ds; + QemuConsole *con; drawfn *line_fn[2]; int dest_width; int xres, yres; @@ -579,6 +579,7 @@ static const MemoryRegionOps pxa2xx_lcdc_ops = { /* Load new palette for a given DMA channel, convert to internal format */ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, n, format, r, g, b, alpha; uint32_t *dest; uint8_t *src; @@ -652,7 +653,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) src += 4; break; } - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: *dest = rgb_to_pixel8(r, g, b) | alpha; break; @@ -676,6 +677,7 @@ static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp) static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) @@ -693,7 +695,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, dest_width, s->dest_width, s->invalidated, @@ -703,6 +705,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) @@ -720,7 +723,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, s->dest_width, -dest_width, s->invalidated, @@ -731,6 +734,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) { @@ -751,7 +755,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, dest_width = s->xres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, -dest_width, -s->dest_width, s->invalidated, @@ -761,6 +765,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s, static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, hwaddr addr, int *miny, int *maxy) { + DisplaySurface *surface = qemu_console_surface(s->con); int src_width, dest_width; drawfn fn = NULL; if (s->dest_width) { @@ -781,7 +786,7 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s, dest_width = s->yres * s->dest_width; *miny = 0; - framebuffer_update_display(s->ds, s->sysmem, + framebuffer_update_display(surface, s->sysmem, addr, s->xres, s->yres, src_width, -s->dest_width, dest_width, s->invalidated, @@ -800,9 +805,9 @@ static void pxa2xx_lcdc_resize(PXA2xxLCDState *s) if (width != s->xres || height != s->yres) { if (s->orientation == 90 || s->orientation == 270) { - qemu_console_resize(s->ds, height, width); + qemu_console_resize(s->con, height, width); } else { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); } s->invalidated = 1; s->xres = width; @@ -871,20 +876,20 @@ static void pxa2xx_update_display(void *opaque) if (miny >= 0) { switch (s->orientation) { case 0: - dpy_gfx_update(s->ds, 0, miny, s->xres, maxy - miny + 1); + dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1); break; case 90: - dpy_gfx_update(s->ds, miny, 0, maxy - miny + 1, s->xres); + dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres); break; case 180: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_gfx_update(s->ds, 0, maxy, s->xres, miny - maxy + 1); + dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1); break; case 270: maxy = s->yres - maxy - 1; miny = s->yres - miny - 1; - dpy_gfx_update(s->ds, maxy, 0, miny - maxy + 1, s->xres); + dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres); break; } } @@ -990,6 +995,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, hwaddr base, qemu_irq irq) { PXA2xxLCDState *s; + DisplaySurface *surface; s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState)); s->invalidated = 1; @@ -1002,11 +1008,12 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, "pxa2xx-lcd-controller", 0x00100000); memory_region_add_subregion(sysmem, base, &s->iomem); - s->ds = graphic_console_init(pxa2xx_update_display, - pxa2xx_invalidate_display, - NULL, NULL, s); + s->con = graphic_console_init(pxa2xx_update_display, + pxa2xx_invalidate_display, + NULL, NULL, s); + surface = qemu_console_surface(s->con); - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: s->dest_width = 0; break; diff --git a/hw/qdev-core.h b/hw/qdev-core.h index 2486f36853..547fbc7e0d 100644 --- a/hw/qdev-core.h +++ b/hw/qdev-core.h @@ -175,6 +175,9 @@ struct Property { uint8_t bitnr; uint8_t qtype; int64_t defval; + int arrayoffset; + PropertyInfo *arrayinfo; + int arrayfieldsize; }; struct PropertyInfo { diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 0307a7830b..247ca6c5b4 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -779,6 +779,110 @@ PropertyInfo qdev_prop_pci_host_devaddr = { .set = set_pci_host_devaddr, }; +/* --- support for array properties --- */ + +/* Used as an opaque for the object properties we add for each + * array element. Note that the struct Property must be first + * in the struct so that a pointer to this works as the opaque + * for the underlying element's property hooks as well as for + * our own release callback. + */ +typedef struct { + struct Property prop; + char *propname; + ObjectPropertyRelease *release; +} ArrayElementProperty; + +/* object property release callback for array element properties: + * we call the underlying element's property release hook, and + * then free the memory we allocated when we added the property. + */ +static void array_element_release(Object *obj, const char *name, void *opaque) +{ + ArrayElementProperty *p = opaque; + if (p->release) { + p->release(obj, name, opaque); + } + g_free(p->propname); + g_free(p); +} + +static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + /* Setter for the property which defines the length of a + * variable-sized property array. As well as actually setting the + * array-length field in the device struct, we have to create the + * array itself and dynamically add the corresponding properties. + */ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint32_t *alenptr = qdev_get_prop_ptr(dev, prop); + void **arrayptr = (void *)dev + prop->arrayoffset; + void *eltptr; + const char *arrayname; + int i; + + if (dev->realized) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + if (*alenptr) { + error_setg(errp, "array size property %s may not be set more than once", + name); + return; + } + visit_type_uint32(v, alenptr, name, errp); + if (error_is_set(errp)) { + return; + } + if (!*alenptr) { + return; + } + + /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix; + * strip it off so we can get the name of the array itself. + */ + assert(strncmp(name, PROP_ARRAY_LEN_PREFIX, + strlen(PROP_ARRAY_LEN_PREFIX)) == 0); + arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX); + + /* Note that it is the responsibility of the individual device's deinit + * to free the array proper. + */ + *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize); + for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) { + char *propname = g_strdup_printf("%s[%d]", arrayname, i); + ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1); + arrayprop->release = prop->arrayinfo->release; + arrayprop->propname = propname; + arrayprop->prop.info = prop->arrayinfo; + arrayprop->prop.name = propname; + /* This ugly piece of pointer arithmetic sets up the offset so + * that when the underlying get/set hooks call qdev_get_prop_ptr + * they get the right answer despite the array element not actually + * being inside the device struct. + */ + arrayprop->prop.offset = eltptr - (void *)dev; + assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr); + object_property_add(obj, propname, + arrayprop->prop.info->name, + arrayprop->prop.info->get, + arrayprop->prop.info->set, + array_element_release, + arrayprop, errp); + if (error_is_set(errp)) { + return; + } + } +} + +PropertyInfo qdev_prop_arraylen = { + .name = "uint32", + .get = get_uint32, + .set = set_prop_arraylen, +}; + /* --- public helpers --- */ static Property *qdev_prop_walk(Property *props, const char *name) diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h index 0b0465c9b3..c9bb246841 100644 --- a/hw/qdev-properties.h +++ b/hw/qdev-properties.h @@ -26,6 +26,7 @@ extern PropertyInfo qdev_prop_vlan; extern PropertyInfo qdev_prop_pci_devfn; extern PropertyInfo qdev_prop_blocksize; extern PropertyInfo qdev_prop_pci_host_devaddr; +extern PropertyInfo qdev_prop_arraylen; #define DEFINE_PROP(_name, _state, _field, _prop, _type) { \ .name = (_name), \ @@ -51,6 +52,44 @@ extern PropertyInfo qdev_prop_pci_host_devaddr; .defval = (bool)_defval, \ } +#define PROP_ARRAY_LEN_PREFIX "len-" + +/** + * DEFINE_PROP_ARRAY: + * @_name: name of the array + * @_state: name of the device state structure type + * @_field: uint32_t field in @_state to hold the array length + * @_arrayfield: field in @_state (of type '@_arraytype *') which + * will point to the array + * @_arrayprop: PropertyInfo defining what property the array elements have + * @_arraytype: C type of the array elements + * + * Define device properties for a variable-length array _name. A + * static property "len-arrayname" is defined. When the device creator + * sets this property to the desired length of array, further dynamic + * properties "arrayname[0]", "arrayname[1]", ... are defined so the + * device creator can set the array element values. Setting the + * "len-arrayname" property more than once is an error. + * + * When the array length is set, the @_field member of the device + * struct is set to the array length, and @_arrayfield is set to point + * to (zero-initialised) memory allocated for the array. For a zero + * length array, @_field will be set to 0 and @_arrayfield to NULL. + * It is the responsibility of the device deinit code to free the + * @_arrayfield memory. + */ +#define DEFINE_PROP_ARRAY(_name, _state, _field, \ + _arrayfield, _arrayprop, _arraytype) { \ + .name = (PROP_ARRAY_LEN_PREFIX _name), \ + .info = &(qdev_prop_arraylen), \ + .offset = offsetof(_state, _field) \ + + type_check(uint32_t, typeof_field(_state, _field)), \ + .qtype = QTYPE_QINT, \ + .arrayinfo = &(_arrayprop), \ + .arrayfieldsize = sizeof(_arraytype), \ + .arrayoffset = offsetof(_state, _arrayfield), \ + } + #define DEFINE_PROP_UINT8(_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t) #define DEFINE_PROP_UINT16(_n, _s, _f, _d) \ diff --git a/hw/qxl-render.c b/hw/qxl-render.c index d77df42b7e..8cd9be434d 100644 --- a/hw/qxl-render.c +++ b/hw/qxl-render.c @@ -23,11 +23,12 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { + DisplaySurface *surface = qemu_console_surface(qxl->vga.con); + uint8_t *dst = surface_data(surface); uint8_t *src; - uint8_t *dst = ds_get_data(qxl->vga.ds); int len, i; - if (is_buffer_shared(qxl->vga.ds->surface)) { + if (is_buffer_shared(surface)) { return; } if (!qxl->guest_primary.data) { @@ -98,6 +99,7 @@ static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) { VGACommonState *vga = &qxl->vga; + DisplaySurface *surface; int i; if (qxl->guest_primary.resized) { @@ -112,8 +114,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.bytes_pp, qxl->guest_primary.bits_pp); if (qxl->guest_primary.qxl_stride > 0) { - qemu_free_displaysurface(vga->ds); - vga->ds->surface = qemu_create_displaysurface_from + surface = qemu_create_displaysurface_from (qxl->guest_primary.surface.width, qxl->guest_primary.surface.height, qxl->guest_primary.bits_pp, @@ -121,18 +122,18 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) qxl->guest_primary.data, false); } else { - qemu_resize_displaysurface(vga->ds, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height); + surface = qemu_create_displaysurface + (qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); } - dpy_gfx_resize(vga->ds); + dpy_gfx_replace_surface(vga->con, surface); } for (i = 0; i < qxl->num_dirty_rects; i++) { if (qemu_spice_rect_is_empty(qxl->dirty+i)) { break; } qxl_blit(qxl, qxl->dirty+i); - dpy_gfx_update(vga->ds, + dpy_gfx_update(vga->con, qxl->dirty[i].left, qxl->dirty[i].top, qxl->dirty[i].right - qxl->dirty[i].left, qxl->dirty[i].bottom - qxl->dirty[i].top); @@ -236,7 +237,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) return 1; } - if (!dpy_cursor_define_supported(qxl->ssd.ds)) { + if (!dpy_cursor_define_supported(qxl->vga.con)) { return 0; } @@ -118,8 +118,6 @@ static QXLMode qxl_modes[] = { QXL_MODE_EX(3200, 2400), }; -static PCIQXLDevice *qxl0; - static void qxl_send_events(PCIQXLDevice *d, uint32_t events); static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async); static void qxl_reset_memslots(PCIQXLDevice *d); @@ -1075,8 +1073,8 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) trace_qxl_enter_vga_mode(d->id); qemu_spice_create_host_primary(&d->ssd); d->mode = QXL_MODE_VGA; - dpy_gfx_resize(d->ssd.ds); vga_dirty_log_start(&d->vga); + vga_hw_update(); } static void qxl_exit_vga_mode(PCIQXLDevice *d) @@ -1784,7 +1782,7 @@ static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch, case QXL_MODE_COMPAT: case QXL_MODE_NATIVE: qxl_render_update(qxl); - ppm_save(filename, qxl->ssd.ds->surface, errp); + ppm_save(filename, qxl->ssd.ds, errp); break; case QXL_MODE_VGA: vga->screen_dump(vga, filename, cswitch, errp); @@ -1866,35 +1864,45 @@ static void qxl_vm_change_state_handler(void *opaque, int running, /* display change listener */ -static void display_update(struct DisplayState *ds, int x, int y, int w, int h) +static void display_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_update(&qxl0->ssd, x, y, w, h); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_update(&qxl->ssd, x, y, w, h); } } -static void display_resize(struct DisplayState *ds) +static void display_switch(DisplayChangeListener *dcl, + struct DisplaySurface *surface) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_resize(&qxl0->ssd); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + qxl->ssd.ds = surface; + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_switch(&qxl->ssd, surface); } } -static void display_refresh(struct DisplayState *ds) +static void display_refresh(DisplayChangeListener *dcl) { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_refresh(&qxl0->ssd); + PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl); + + if (qxl->mode == QXL_MODE_VGA) { + qemu_spice_display_refresh(&qxl->ssd); } else { - qemu_mutex_lock(&qxl0->ssd.lock); - qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); - qemu_mutex_unlock(&qxl0->ssd.lock); + qemu_mutex_lock(&qxl->ssd.lock); + qemu_spice_cursor_refresh_unlocked(&qxl->ssd); + qemu_mutex_unlock(&qxl->ssd.lock); } } -static DisplayChangeListener display_listener = { +static DisplayChangeListenerOps display_listener_ops = { + .dpy_name = "spice/qxl", .dpy_gfx_update = display_update, - .dpy_gfx_resize = display_resize, - .dpy_refresh = display_refresh, + .dpy_gfx_switch = display_switch, + .dpy_refresh = display_refresh, }; static void qxl_init_ramsize(PCIQXLDevice *qxl) @@ -2055,6 +2063,7 @@ static int qxl_init_primary(PCIDevice *dev) PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); VGACommonState *vga = &qxl->vga; PortioList *qxl_vga_port_list = g_new(PortioList, 1); + DisplayState *ds; int rc; qxl->id = 0; @@ -2065,18 +2074,20 @@ static int qxl_init_primary(PCIDevice *dev) portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); - vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, - qxl_hw_screen_dump, qxl_hw_text_update, qxl); - qemu_spice_display_init_common(&qxl->ssd, vga->ds); - - qxl0 = qxl; + vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, + qxl_hw_screen_dump, qxl_hw_text_update, + qxl); + qxl->ssd.con = vga->con, + qemu_spice_display_init_common(&qxl->ssd); rc = qxl_init_common(qxl); if (rc != 0) { return rc; } - register_displaychangelistener(vga->ds, &display_listener); + qxl->ssd.dcl.ops = &display_listener_ops; + ds = qemu_console_displaystate(vga->con); + register_displaychangelistener(ds, &qxl->ssd.dcl); return rc; } diff --git a/hw/sm501.c b/hw/sm501.c index 0e019111bb..93a06c90b9 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -454,7 +454,7 @@ static const uint32_t sm501_mem_local_size[] = { typedef struct SM501State { /* graphic console status */ - DisplayState *ds; + QemuConsole *con; /* status & internal resources */ hwaddr base; @@ -1234,9 +1234,9 @@ static draw_hwc_line_func * draw_hwc_line_funcs[] = { draw_hwc_line_16bgr, }; -static inline int get_depth_index(DisplayState *s) +static inline int get_depth_index(DisplaySurface *surface) { - switch(ds_get_bits_per_pixel(s)) { + switch (surface_bits_per_pixel(surface)) { default: case 8: return 0; @@ -1245,26 +1245,28 @@ static inline int get_depth_index(DisplayState *s) case 16: return 2; case 32: - if (is_surface_bgr(s->surface)) - return 4; - else - return 3; + if (is_surface_bgr(surface)) { + return 4; + } else { + return 3; + } } } static void sm501_draw_crt(SM501State * s) { + DisplaySurface *surface = qemu_console_surface(s->con); int y; int width = (s->dc_crt_h_total & 0x00000FFF) + 1; int height = (s->dc_crt_v_total & 0x00000FFF) + 1; uint8_t * src = s->local_mem; int src_bpp = 0; - int dst_bpp = ds_get_bytes_per_pixel(s->ds) + (ds_get_bits_per_pixel(s->ds) % 8 ? 1 : 0); + int dst_bpp = surface_bytes_per_pixel(surface); uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE - SM501_DC_PANEL_PALETTE]; uint8_t hwc_palette[3 * 3]; - int ds_depth_index = get_depth_index(s->ds); + int ds_depth_index = get_depth_index(surface); draw_line_func * draw_line = NULL; draw_hwc_line_func * draw_hwc_line = NULL; int full_update = 0; @@ -1312,7 +1314,8 @@ static void sm501_draw_crt(SM501State * s) /* adjust console size */ if (s->last_width != width || s->last_height != height) { - qemu_console_resize(s->ds, width, height); + qemu_console_resize(s->con, width, height); + surface = qemu_console_surface(s->con); s->last_width = width; s->last_height = height; full_update = 1; @@ -1331,7 +1334,8 @@ static void sm501_draw_crt(SM501State * s) /* draw line and change status */ if (update) { - uint8_t * d = &(ds_get_data(s->ds)[y * width * dst_bpp]); + uint8_t *d = surface_data(surface); + d += y * width * dst_bpp; /* draw graphics layer */ draw_line(d, src, width, palette); @@ -1350,7 +1354,7 @@ static void sm501_draw_crt(SM501State * s) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->con, 0, y_start, width, y - y_start); y_start = -1; } } @@ -1361,7 +1365,7 @@ static void sm501_draw_crt(SM501State * s) /* complete flush to display */ if (y_start >= 0) - dpy_gfx_update(s->ds, 0, y_start, width, y - y_start); + dpy_gfx_update(s->con, 0, y_start, width, y - y_start); /* clear dirty flags */ if (page_min != ~0l) { @@ -1441,6 +1445,6 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, } /* create qemu graphic console */ - s->ds = graphic_console_init(sm501_update_display, NULL, - NULL, NULL, s); + s->con = graphic_console_init(sm501_update_display, NULL, + NULL, NULL, s); } diff --git a/hw/ssd0303.c b/hw/ssd0303.c index db50909734..68d1f24b06 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -43,7 +43,7 @@ enum ssd0303_cmd { typedef struct { I2CSlave i2c; - DisplayState *ds; + QemuConsole *con; int row; int col; int start_line; @@ -191,6 +191,7 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event) static void ssd0303_update_display(void *opaque) { ssd0303_state *s = (ssd0303_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *dest; uint8_t *src; int x; @@ -204,7 +205,7 @@ static void ssd0303_update_display(void *opaque) if (!s->redraw) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 15: @@ -236,7 +237,7 @@ static void ssd0303_update_display(void *opaque) colors[0] = colortab + dest_width; colors[1] = colortab; } - dest = ds_get_data(s->ds); + dest = surface_data(surface); for (y = 0; y < 16; y++) { line = (y + s->start_line) & 63; src = s->framebuffer + 132 * (line >> 3) + 36; @@ -252,7 +253,7 @@ static void ssd0303_update_display(void *opaque) } } s->redraw = 0; - dpy_gfx_update(s->ds, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); + dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY); } static void ssd0303_invalidate_display(void * opaque) @@ -287,10 +288,10 @@ static int ssd0303_init(I2CSlave *i2c) { ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c); - s->ds = graphic_console_init(ssd0303_update_display, - ssd0303_invalidate_display, - NULL, NULL, s); - qemu_console_resize(s->ds, 96 * MAGNIFY, 16 * MAGNIFY); + s->con = graphic_console_init(ssd0303_update_display, + ssd0303_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY); return 0; } diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 27b4151994..5cf2f7058f 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -45,7 +45,7 @@ enum ssd0323_mode typedef struct { SSISlave ssidev; - DisplayState *ds; + QemuConsole *con; int cmd_len; int cmd; @@ -175,6 +175,7 @@ static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data) static void ssd0323_update_display(void *opaque) { ssd0323_state *s = (ssd0323_state *)opaque; + DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *dest; uint8_t *src; int x; @@ -189,7 +190,7 @@ static void ssd0323_update_display(void *opaque) if (!s->redraw) return; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 0: return; case 15: @@ -212,7 +213,7 @@ static void ssd0323_update_display(void *opaque) for (i = 0; i < 16; i++) { int n; colors[i] = p; - switch (ds_get_bits_per_pixel(s->ds)) { + switch (surface_bits_per_pixel(surface)) { case 15: n = i * 2 + (i >> 3); p[0] = n | (n << 5); @@ -235,7 +236,7 @@ static void ssd0323_update_display(void *opaque) p += dest_width; } /* TODO: Implement row/column remapping. */ - dest = ds_get_data(s->ds); + dest = surface_data(surface); for (y = 0; y < 64; y++) { line = y; src = s->framebuffer + 64 * line; @@ -260,7 +261,7 @@ static void ssd0323_update_display(void *opaque) } } s->redraw = 0; - dpy_gfx_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); + dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); } static void ssd0323_invalidate_display(void * opaque) @@ -336,10 +337,10 @@ static int ssd0323_init(SSISlave *dev) s->col_end = 63; s->row_end = 79; - s->ds = graphic_console_init(ssd0323_update_display, - ssd0323_invalidate_display, - NULL, NULL, s); - qemu_console_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); + s->con = graphic_console_init(ssd0323_update_display, + ssd0323_invalidate_display, + NULL, NULL, s); + qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index 0755463a1d..79c971b439 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -125,7 +125,7 @@ struct TC6393xbState { DeviceState *flash; ECCState ecc; - DisplayState *ds; + QemuConsole *con; MemoryRegion vram; uint16_t *vram_ptr; uint32_t scr_width, scr_height; /* in pixels */ @@ -433,7 +433,9 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) { - switch (ds_get_bits_per_pixel(s->ds)) { + DisplaySurface *surface = qemu_console_surface(s->con); + + switch (surface_bits_per_pixel(surface)) { case 8: tc6393xb_draw_graphic8(s); break; @@ -450,34 +452,37 @@ static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update) tc6393xb_draw_graphic32(s); break; default: - printf("tc6393xb: unknown depth %d\n", ds_get_bits_per_pixel(s->ds)); + printf("tc6393xb: unknown depth %d\n", + surface_bits_per_pixel(surface)); return; } - dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_draw_blank(TC6393xbState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *d; if (!full_update) return; - w = s->scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + w = s->scr_width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for(i = 0; i < s->scr_height; i++) { memset(d, 0, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, s->scr_width, s->scr_height); + dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height); } static void tc6393xb_update_display(void *opaque) { TC6393xbState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int full_update; if (s->scr_width == 0 || s->scr_height == 0) @@ -488,8 +493,9 @@ static void tc6393xb_update_display(void *opaque) s->blanked = s->blank; full_update = 1; } - if (s->scr_width != ds_get_width(s->ds) || s->scr_height != ds_get_height(s->ds)) { - qemu_console_resize(s->ds, s->scr_width, s->scr_height); + if (s->scr_width != surface_width(surface) || + s->scr_height != surface_height(surface)) { + qemu_console_resize(s->con, s->scr_width, s->scr_height); full_update = 1; } if (s->blanked) @@ -577,7 +583,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); s->scr_width = 480; s->scr_height = 640; - s->ds = graphic_console_init(tc6393xb_update_display, + s->con = graphic_console_init(tc6393xb_update_display, NULL, /* invalidate */ NULL, /* screen_dump */ NULL, /* text_update */ diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h index 4cbbad5dae..154aafd400 100644 --- a/hw/tc6393xb_template.h +++ b/hw/tc6393xb_template.h @@ -37,17 +37,18 @@ static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; uint16_t *data_buffer; uint8_t *data_display; data_buffer = s->vram_ptr; - data_display = ds_get_data(s->ds); + data_display = surface_data(surface); for(i = 0; i < s->scr_height; i++) { #if (BITS == 16) memcpy(data_display, data_buffer, s->scr_width * 2); data_buffer += s->scr_width; - data_display += ds_get_linesize(s->ds); + data_display += surface_stride(surface); #else int j; for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) { @@ -38,7 +38,7 @@ typedef struct TCXState { SysBusDevice busdev; hwaddr addr; - DisplayState *ds; + QemuConsole *con; uint8_t *vram; uint32_t *vram24, *cplane; MemoryRegion vram_mem; @@ -75,9 +75,11 @@ static void tcx24_set_dirty(TCXState *s) static void update_palette_entries(TCXState *s, int start, int end) { + DisplaySurface *surface = qemu_console_surface(s->con); int i; - for(i = start; i < end; i++) { - switch(ds_get_bits_per_pixel(s->ds)) { + + for (i = start; i < end; i++) { + switch (surface_bits_per_pixel(surface)) { default: case 8: s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]); @@ -89,10 +91,11 @@ static void update_palette_entries(TCXState *s, int start, int end) s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]); break; case 32: - if (is_surface_bgr(s->ds->surface)) + if (is_surface_bgr(surface)) { s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]); - else + } else { s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]); + } break; } } @@ -151,12 +154,13 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d, const uint32_t *cplane, const uint32_t *s24) { + DisplaySurface *surface = qemu_console_surface(s1->con); int x, bgr, r, g, b; uint8_t val, *p8; uint32_t *p = (uint32_t *)d; uint32_t dval; - bgr = is_surface_bgr(s1->ds->surface); + bgr = is_surface_bgr(surface); for(x = 0; x < width; x++, s++, s24++) { if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct, BGR order @@ -213,23 +217,26 @@ static inline void reset_dirty(TCXState *ts, ram_addr_t page_min, static void tcx_update_display(void *opaque) { TCXState *ts = opaque; + DisplaySurface *surface = qemu_console_surface(ts->con); ram_addr_t page, page_min, page_max; int y, y_start, dd, ds; uint8_t *d, *s; void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width); - if (ds_get_bits_per_pixel(ts->ds) == 0) + if (surface_bits_per_pixel(surface) == 0) { return; + } + page = 0; y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(ts->ds); + d = surface_data(surface); s = ts->vram; - dd = ds_get_linesize(ts->ds); + dd = surface_stride(surface); ds = 1024; - switch (ds_get_bits_per_pixel(ts->ds)) { + switch (surface_bits_per_pixel(surface)) { case 32: f = tcx_draw_line32; break; @@ -269,7 +276,7 @@ static void tcx_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); y_start = -1; } @@ -279,7 +286,7 @@ static void tcx_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); } /* reset modified pages */ @@ -293,24 +300,27 @@ static void tcx_update_display(void *opaque) static void tcx24_update_display(void *opaque) { TCXState *ts = opaque; + DisplaySurface *surface = qemu_console_surface(ts->con); ram_addr_t page, page_min, page_max, cpage, page24; int y, y_start, dd, ds; uint8_t *d, *s; uint32_t *cptr, *s24; - if (ds_get_bits_per_pixel(ts->ds) != 32) + if (surface_bits_per_pixel(surface) != 32) { return; + } + page = 0; page24 = ts->vram24_offset; cpage = ts->cplane_offset; y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(ts->ds); + d = surface_data(surface); s = ts->vram; s24 = ts->vram24; cptr = ts->cplane; - dd = ds_get_linesize(ts->ds); + dd = surface_stride(surface); ds = 1024; for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE, @@ -345,7 +355,7 @@ static void tcx24_update_display(void *opaque) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); y_start = -1; } @@ -357,7 +367,7 @@ static void tcx24_update_display(void *opaque) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(ts->ds, 0, y_start, + dpy_gfx_update(ts->con, 0, y_start, ts->width, y - y_start); } /* reset modified pages */ @@ -371,7 +381,7 @@ static void tcx_invalidate_display(void *opaque) TCXState *s = opaque; tcx_set_dirty(s); - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); } static void tcx24_invalidate_display(void *opaque) @@ -380,7 +390,7 @@ static void tcx24_invalidate_display(void *opaque) tcx_set_dirty(s); tcx24_set_dirty(s); - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); } static int vmstate_tcx_post_load(void *opaque, int version_id) @@ -558,21 +568,21 @@ static int tcx_init1(SysBusDevice *dev) &s->vram_mem, vram_offset, size); sysbus_init_mmio(dev, &s->vram_cplane); - s->ds = graphic_console_init(tcx24_update_display, - tcx24_invalidate_display, - tcx24_screen_dump, NULL, s); + s->con = graphic_console_init(tcx24_update_display, + tcx24_invalidate_display, + tcx24_screen_dump, NULL, s); } else { /* THC 8 bit (dummy) */ memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8", TCX_THC_NREGS_8); sysbus_init_mmio(dev, &s->thc8); - s->ds = graphic_console_init(tcx_update_display, - tcx_invalidate_display, - tcx_screen_dump, NULL, s); + s->con = graphic_console_init(tcx_update_display, + tcx_invalidate_display, + tcx_screen_dump, NULL, s); } - qemu_console_resize(s->ds, s->width, s->height); + qemu_console_resize(s->con, s->width, s->height); return 0; } diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c index 4aa62bf35e..02356d4d58 100644 --- a/hw/vga-isa-mm.c +++ b/hw/vga-isa-mm.c @@ -135,8 +135,9 @@ int isa_vga_mm_init(hwaddr vram_base, vga_common_init(&s->vga); vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, s); + s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate, + s->vga.screen_dump, s->vga.text_update, + s); vga_init_vbe(&s->vga, address_space); return 0; diff --git a/hw/vga-isa.c b/hw/vga-isa.c index ffad5226fd..9e293217d0 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -62,8 +62,8 @@ static int vga_initfn(ISADevice *dev) isa_mem_base + 0x000a0000, vga_io_memory, 1); memory_region_set_coalescing(vga_io_memory); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); vga_init_vbe(s, isa_address_space(dev)); /* ROM BIOS */ diff --git a/hw/vga-pci.c b/hw/vga-pci.c index 18018ff1c3..05fa9bcb64 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -150,8 +150,8 @@ static int pci_std_vga_initfn(PCIDevice *dev) vga_common_init(s); vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true); - s->ds = graphic_console_init(s->update, s->invalidate, - s->screen_dump, s->text_update, s); + s->con = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, s); /* XXX: VGA_RAM_SIZE must be a power of two */ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); @@ -1174,9 +1174,9 @@ static int update_basic_params(VGACommonState *s) #define NB_DEPTHS 7 -static inline int get_depth_index(DisplayState *s) +static inline int get_depth_index(DisplaySurface *s) { - switch(ds_get_bits_per_pixel(s)) { + switch (surface_bits_per_pixel(s)) { default: case 8: return 0; @@ -1185,10 +1185,11 @@ static inline int get_depth_index(DisplayState *s) case 16: return 2; case 32: - if (is_surface_bgr(s->surface)) + if (is_surface_bgr(s)) { return 4; - else + } else { return 3; + } } } @@ -1294,6 +1295,7 @@ static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = { */ static void vga_draw_text(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; int cx_min, cx_max, linesize, x_incr, line, line1; uint32_t offset, fgcol, bgcol, v, cursor_offset; @@ -1345,8 +1347,9 @@ static void vga_draw_text(VGACommonState *s, int full_update) cw != s->last_cw || cheight != s->last_ch || s->last_depth) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); - dpy_text_resize(s->ds, width, height); + qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); + surface = qemu_console_surface(s->con); + dpy_text_resize(s->con, width, height); s->last_depth = 0; s->last_width = width; s->last_height = height; @@ -1355,10 +1358,10 @@ static void vga_draw_text(VGACommonState *s, int full_update) full_update = 1; } s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + rgb_to_pixel_dup_table[get_depth_index(surface)]; full_update |= update_palette16(s); palette = s->last_palette; - x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); + x_incr = cw * surface_bytes_per_pixel(surface); if (full_update) { s->full_update_text = 1; @@ -1389,15 +1392,15 @@ static void vga_draw_text(VGACommonState *s, int full_update) s->cursor_visible_phase = !s->cursor_visible_phase; } - depth_index = get_depth_index(s->ds); + depth_index = get_depth_index(surface); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; - dest = ds_get_data(s->ds); - linesize = ds_get_linesize(s->ds); + dest = surface_data(surface); + linesize = surface_stride(surface); ch_attr_ptr = s->last_ch_attr; line = 0; offset = s->start_addr * 4; @@ -1465,7 +1468,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) ch_attr_ptr++; } if (cx_max != -1) { - dpy_gfx_update(s->ds, cx_min * cw, cy * cheight, + dpy_gfx_update(s->con, cx_min * cw, cy * cheight, (cx_max - cx_min + 1) * cw, cheight); } dest += linesize * cheight; @@ -1636,6 +1639,7 @@ void vga_dirty_log_stop(VGACommonState *s) */ static void vga_draw_graphic(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int y1, y, update, linesize, y_start, double_scan, mask, depth; int width, height, shift_control, line_offset, bwidth, bits; ram_addr_t page0, page1, page_min, page_max; @@ -1691,13 +1695,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) height != s->last_height || s->last_depth != depth) { if (depth == 32 || (depth == 16 && !byteswap)) { - qemu_free_displaysurface(s->ds); - s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth, - s->line_offset, + surface = qemu_create_displaysurface_from(disp_width, + height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_resize(s->ds); + dpy_gfx_replace_surface(s->con, surface); } else { - qemu_console_resize(s->ds, disp_width, height); + qemu_console_resize(s->con, disp_width, height); + surface = qemu_console_surface(s->con); } s->last_scr_width = disp_width; s->last_scr_height = height; @@ -1706,19 +1710,18 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->last_line_offset = s->line_offset; s->last_depth = depth; full_update = 1; - } else if (is_buffer_shared(s->ds->surface) && - (full_update || ds_get_data(s->ds) != s->vram_ptr + } else if (is_buffer_shared(surface) && + (full_update || surface_data(surface) != s->vram_ptr + (s->start_addr * 4))) { - qemu_free_displaysurface(s->ds); - s->ds->surface = qemu_create_displaysurface_from(disp_width, - height, depth, - s->line_offset, + DisplaySurface *surface; + surface = qemu_create_displaysurface_from(disp_width, + height, depth, s->line_offset, s->vram_ptr + (s->start_addr * 4), byteswap); - dpy_gfx_setdata(s->ds); + dpy_gfx_replace_surface(s->con, surface); } s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; + rgb_to_pixel_dup_table[get_depth_index(surface)]; if (shift_control == 0) { full_update |= update_palette16(s); @@ -1767,10 +1770,12 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) break; } } - vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; + vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + + get_depth_index(surface)]; - if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate) + if (!is_buffer_shared(surface) && s->cursor_invalidate) { s->cursor_invalidate(s); + } line_offset = s->line_offset; #if 0 @@ -1783,8 +1788,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) y_start = -1; page_min = -1; page_max = 0; - d = ds_get_data(s->ds); - linesize = ds_get_linesize(s->ds); + d = surface_data(surface); + linesize = surface_stride(surface); y1 = 0; for(y = 0; y < height; y++) { addr = addr1; @@ -1811,7 +1816,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) page_min = page0; if (page1 > page_max) page_max = page1; - if (!(is_buffer_shared(s->ds->surface))) { + if (!(is_buffer_shared(surface))) { vga_draw_line(s, d, s->vram_ptr + addr, width); if (s->cursor_draw_line) s->cursor_draw_line(s, d, y); @@ -1819,7 +1824,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } else { if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, + dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); y_start = -1; } @@ -1840,7 +1845,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } if (y_start >= 0) { /* flush to display */ - dpy_gfx_update(s->ds, 0, y_start, + dpy_gfx_update(s->con, 0, y_start, disp_width, y - y_start); } /* reset modified pages */ @@ -1855,6 +1860,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) static void vga_draw_blank(VGACommonState *s, int full_update) { + DisplaySurface *surface = qemu_console_surface(s->con); int i, w, val; uint8_t *d; @@ -1864,18 +1870,19 @@ static void vga_draw_blank(VGACommonState *s, int full_update) return; s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - if (ds_get_bits_per_pixel(s->ds) == 8) + rgb_to_pixel_dup_table[get_depth_index(surface)]; + if (surface_bits_per_pixel(surface) == 8) { val = s->rgb_to_pixel(0, 0, 0); - else + } else { val = 0; - w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - d = ds_get_data(s->ds); + } + w = s->last_scr_width * surface_bytes_per_pixel(surface); + d = surface_data(surface); for(i = 0; i < s->last_scr_height; i++) { memset(d, val, w); - d += ds_get_linesize(s->ds); + d += surface_stride(surface); } - dpy_gfx_update(s->ds, 0, 0, + dpy_gfx_update(s->con, 0, 0, s->last_scr_width, s->last_scr_height); } @@ -1886,11 +1893,12 @@ static void vga_draw_blank(VGACommonState *s, int full_update) static void vga_update_display(void *opaque) { VGACommonState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); int full_update, graphic_mode; qemu_flush_coalesced_mmio_buffer(); - if (ds_get_bits_per_pixel(s->ds) == 0) { + if (surface_bits_per_pixel(surface) == 0) { /* nothing to do */ } else { full_update = 0; @@ -2064,8 +2072,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) cw != s->last_cw || cheight != s->last_ch) { s->last_scr_width = width * cw; s->last_scr_height = height * cheight; - qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height); - dpy_text_resize(s->ds, width, height); + qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height); + dpy_text_resize(s->con, width, height); s->last_depth = 0; s->last_width = width; s->last_height = height; @@ -2090,11 +2098,11 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) { cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20); if (cursor_visible && cursor_offset < size && cursor_offset >= 0) - dpy_text_cursor(s->ds, + dpy_text_cursor(s->con, TEXTMODE_X(cursor_offset), TEXTMODE_Y(cursor_offset)); else - dpy_text_cursor(s->ds, -1, -1); + dpy_text_cursor(s->con, -1, -1); s->cursor_offset = cursor_offset; s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; @@ -2107,7 +2115,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; src ++, dst ++, i ++) console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src))); - dpy_text_update(s->ds, 0, 0, width, height); + dpy_text_update(s->con, 0, 0, width, height); } else { c_max = 0; @@ -2130,7 +2138,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) if (c_min <= c_max) { i = TEXTMODE_Y(c_min); - dpy_text_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1); + dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1); } } @@ -2155,8 +2163,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) /* Display a message */ s->last_width = 60; s->last_height = height = 3; - dpy_text_cursor(s->ds, -1, -1); - dpy_text_resize(s->ds, s->last_width, height); + dpy_text_cursor(s->con, -1, -1); + dpy_text_resize(s->con, s->last_width, height); for (dst = chardata, i = 0; i < s->last_width * height; i ++) console_write_ch(dst ++, ' '); @@ -2167,7 +2175,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) for (i = 0; i < size; i ++) console_write_ch(dst ++, 0x00200100 | msg_buffer[i]); - dpy_text_update(s->ds, 0, 0, s->last_width, height); + dpy_text_update(s->con, 0, 0, s->last_width, height); } static uint64_t vga_mem_read(void *opaque, hwaddr addr, @@ -2439,10 +2447,11 @@ static void vga_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { VGACommonState *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->con); if (cswitch) { vga_invalidate_display(s); } vga_hw_update(); - ppm_save(filename, s->ds->surface, errp); + ppm_save(filename, surface, errp); } diff --git a/hw/vga_int.h b/hw/vga_int.h index 8d496ea9bf..260f7d6948 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -132,7 +132,7 @@ typedef struct VGACommonState { uint32_t vbe_bank_mask; int vbe_mapped; /* display refresh support */ - DisplayState *ds; + QemuConsole *con; uint32_t font_offsets[2]; int graphic_mode; uint8_t shift_control; diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index db2f187e56..5b9ce8f96b 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -57,9 +57,6 @@ struct vmsvga_state_s { int new_height; uint32_t guest; uint32_t svgaid; - uint32_t wred; - uint32_t wgreen; - uint32_t wblue; int syncing; MemoryRegion fifo_ram; @@ -289,6 +286,7 @@ enum { static inline void vmsvga_update_rect(struct vmsvga_state_s *s, int x, int y, int w, int h) { + DisplaySurface *surface = qemu_console_surface(s->vga.con); int line; int bypl; int width; @@ -305,11 +303,11 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w); w = 0; } - if (x + w > ds_get_width(s->vga.ds)) { + if (x + w > surface_width(surface)) { fprintf(stderr, "%s: update width too large x: %d, w: %d\n", __func__, x, w); - x = MIN(x, ds_get_width(s->vga.ds)); - w = ds_get_width(s->vga.ds) - x; + x = MIN(x, surface_width(surface)); + w = surface_width(surface) - x; } if (y < 0) { @@ -321,23 +319,23 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h); h = 0; } - if (y + h > ds_get_height(s->vga.ds)) { + if (y + h > surface_height(surface)) { fprintf(stderr, "%s: update height too large y: %d, h: %d\n", __func__, y, h); - y = MIN(y, ds_get_height(s->vga.ds)); - h = ds_get_height(s->vga.ds) - y; + y = MIN(y, surface_height(surface)); + h = surface_height(surface) - y; } - bypl = ds_get_linesize(s->vga.ds); - width = ds_get_bytes_per_pixel(s->vga.ds) * w; - start = ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; + bypl = surface_stride(surface); + width = surface_bytes_per_pixel(surface) * w; + start = surface_bytes_per_pixel(surface) * x + bypl * y; src = s->vga.vram_ptr + start; - dst = ds_get_data(s->vga.ds) + start; + dst = surface_data(surface) + start; for (line = h; line > 0; line--, src += bypl, dst += bypl) { memcpy(dst, src, width); } - dpy_gfx_update(s->vga.ds, x, y, w, h); + dpy_gfx_update(s->vga.con, x, y, w, h); } static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s, @@ -373,9 +371,10 @@ static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s) static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, int x0, int y0, int x1, int y1, int w, int h) { + DisplaySurface *surface = qemu_console_surface(s->vga.con); uint8_t *vram = s->vga.vram_ptr; - int bypl = ds_get_linesize(s->vga.ds); - int bypp = ds_get_bytes_per_pixel(s->vga.ds); + int bypl = surface_stride(surface); + int bypp = surface_bytes_per_pixel(surface); int width = bypp * w; int line = h; uint8_t *ptr[2]; @@ -402,8 +401,9 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s, static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, uint32_t c, int x, int y, int w, int h) { - int bypl = ds_get_linesize(s->vga.ds); - int width = ds_get_bytes_per_pixel(s->vga.ds) * w; + DisplaySurface *surface = qemu_console_surface(s->vga.con); + int bypl = surface_stride(surface); + int width = surface_bytes_per_pixel(surface) * w; int line = h; int column; uint8_t *fst; @@ -416,14 +416,14 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s, col[2] = c >> 16; col[3] = c >> 24; - fst = s->vga.vram_ptr + ds_get_bytes_per_pixel(s->vga.ds) * x + bypl * y; + fst = s->vga.vram_ptr + surface_bytes_per_pixel(surface) * x + bypl * y; if (line--) { dst = fst; src = col; for (column = width; column > 0; column--) { *(dst++) = *(src++); - if (src - col == ds_get_bytes_per_pixel(s->vga.ds)) { + if (src - col == surface_bytes_per_pixel(surface)) { src = col; } } @@ -490,7 +490,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s, qc = cursor_builtin_left_ptr(); } - dpy_cursor_define(s->vga.ds, qc); + dpy_cursor_define(s->vga.con, qc); cursor_put(qc); } #endif @@ -720,6 +720,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) { uint32_t caps; struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); switch (s->index) { case SVGA_REG_ID: @@ -729,10 +730,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return s->enable; case SVGA_REG_WIDTH: - return ds_get_width(s->vga.ds); + return surface_width(surface); case SVGA_REG_HEIGHT: - return ds_get_height(s->vga.ds); + return surface_height(surface); case SVGA_REG_MAX_WIDTH: return SVGA_MAX_WIDTH; @@ -750,13 +751,13 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) return 0x0; case SVGA_REG_RED_MASK: - return s->wred; + return surface->pf.rmask; case SVGA_REG_GREEN_MASK: - return s->wgreen; + return surface->pf.gmask; case SVGA_REG_BLUE_MASK: - return s->wblue; + return surface->pf.bmask; case SVGA_REG_BYTES_PER_LINE: return s->bypp * s->new_width; @@ -785,7 +786,7 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address) caps |= SVGA_CAP_RECT_FILL; #endif #ifdef HW_MOUSE_ACCEL - if (dpy_cursor_define_supported(s->vga.ds)) { + if (dpy_cursor_define_supported(s->vga.con)) { caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 | SVGA_CAP_CURSOR_BYPASS; } @@ -947,7 +948,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE); #ifdef HW_MOUSE_ACCEL if (value <= SVGA_CURSOR_ON_SHOW) { - dpy_mouse_set(s->vga.ds, s->cursor.x, s->cursor.y, s->cursor.on); + dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on); } #endif break; @@ -982,9 +983,11 @@ static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data) static inline void vmsvga_check_size(struct vmsvga_state_s *s) { - if (s->new_width != ds_get_width(s->vga.ds) || - s->new_height != ds_get_height(s->vga.ds)) { - qemu_console_resize(s->vga.ds, s->new_width, s->new_height); + DisplaySurface *surface = qemu_console_surface(s->vga.con); + + if (s->new_width != surface_width(surface) || + s->new_height != surface_height(surface)) { + qemu_console_resize(s->vga.con, s->new_width, s->new_height); s->invalidated = 1; } } @@ -992,6 +995,7 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s) static void vmsvga_update_display(void *opaque) { struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); bool dirty = false; if (!s->enable) { @@ -1011,19 +1015,19 @@ static void vmsvga_update_display(void *opaque) if (memory_region_is_logging(&s->vga.vram)) { vga_sync_dirty_bitmap(&s->vga); dirty = memory_region_get_dirty(&s->vga.vram, 0, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + surface_stride(surface) * surface_height(surface), DIRTY_MEMORY_VGA); } if (s->invalidated || dirty) { s->invalidated = 0; - memcpy(ds_get_data(s->vga.ds), s->vga.vram_ptr, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds)); - dpy_gfx_update(s->vga.ds, 0, 0, - ds_get_width(s->vga.ds), ds_get_height(s->vga.ds)); + memcpy(surface_data(surface), s->vga.vram_ptr, + surface_stride(surface) * surface_height(surface)); + dpy_gfx_update(s->vga.con, 0, 0, + surface_width(surface), surface_height(surface)); } if (dirty) { memory_region_reset_dirty(&s->vga.vram, 0, - ds_get_linesize(s->vga.ds) * ds_get_height(s->vga.ds), + surface_stride(surface) * surface_height(surface), DIRTY_MEMORY_VGA); } } @@ -1063,17 +1067,19 @@ static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch, Error **errp) { struct vmsvga_state_s *s = opaque; + DisplaySurface *surface = qemu_console_surface(s->vga.con); + if (!s->enable) { s->vga.screen_dump(&s->vga, filename, cswitch, errp); return; } - if (ds_get_bits_per_pixel(s->vga.ds) == 32) { + if (surface_bits_per_pixel(surface) == 32) { DisplaySurface *ds = qemu_create_displaysurface_from( - ds_get_width(s->vga.ds), - ds_get_height(s->vga.ds), + surface_width(surface), + surface_height(surface), 32, - ds_get_linesize(s->vga.ds), + surface_stride(surface), s->vga.vram_ptr, false); ppm_save(filename, ds, errp); g_free(ds); @@ -1143,14 +1149,16 @@ static const VMStateDescription vmstate_vmware_vga = { static void vmsvga_init(struct vmsvga_state_s *s, MemoryRegion *address_space, MemoryRegion *io) { + DisplaySurface *surface; + s->scratch_size = SVGA_SCRATCH_SIZE; s->scratch = g_malloc(s->scratch_size * 4); - s->vga.ds = graphic_console_init(vmsvga_update_display, - vmsvga_invalidate_display, - vmsvga_screen_dump, - vmsvga_text_update, s); - + s->vga.con = graphic_console_init(vmsvga_update_display, + vmsvga_invalidate_display, + vmsvga_screen_dump, + vmsvga_text_update, s); + surface = qemu_console_surface(s->vga.con); s->fifo_size = SVGA_FIFO_SIZE; memory_region_init_ram(&s->fifo_ram, "vmsvga.fifo", s->fifo_size); @@ -1162,11 +1170,8 @@ static void vmsvga_init(struct vmsvga_state_s *s, vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); /* Save some values here in case they are changed later. * This is suspicious and needs more though why it is needed. */ - s->depth = ds_get_bits_per_pixel(s->vga.ds); - s->bypp = ds_get_bytes_per_pixel(s->vga.ds); - s->wred = ds_get_rmask(s->vga.ds); - s->wgreen = ds_get_gmask(s->vga.ds); - s->wblue = ds_get_bmask(s->vga.ds); + s->depth = surface_bits_per_pixel(surface); + s->bypp = surface_bytes_per_pixel(surface); } static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/xenfb.c b/hw/xenfb.c index 3462ded619..7c46a2fa1e 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -54,7 +54,7 @@ struct common { struct XenDevice xendev; /* must be first */ void *page; - DisplayState *ds; + QemuConsole *con; }; struct XenInput { @@ -318,8 +318,9 @@ static void xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state) { struct XenInput *xenfb = opaque; - int dw = ds_get_width(xenfb->c.ds); - int dh = ds_get_height(xenfb->c.ds); + DisplaySurface *surface = qemu_console_surface(xenfb->c.con); + int dw = surface_width(surface); + int dh = surface_height(surface); int i; if (xenfb->abs_pointer_wanted) @@ -353,16 +354,9 @@ static int input_initialise(struct XenDevice *xendev) struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); int rc; - if (!in->c.ds) { - char *vfb = xenstore_read_str(NULL, "device/vfb"); - if (vfb == NULL) { - /* there is no vfb, run vkbd on its own */ - in->c.ds = get_displaystate(); - } else { - g_free(vfb); - xen_be_printf(xendev, 1, "ds not set (yet)\n"); - return -1; - } + if (!in->c.con) { + xen_be_printf(xendev, 1, "ds not set (yet)\n"); + return -1; } rc = common_bind(&in->c); @@ -615,12 +609,13 @@ static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim, */ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) { + DisplaySurface *surface = qemu_console_surface(xenfb->c.con); int line, oops = 0; - int bpp = ds_get_bits_per_pixel(xenfb->c.ds); - int linesize = ds_get_linesize(xenfb->c.ds); - uint8_t *data = ds_get_data(xenfb->c.ds); + int bpp = surface_bits_per_pixel(surface); + int linesize = surface_stride(surface); + uint8_t *data = surface_data(surface); - if (!is_buffer_shared(xenfb->c.ds->surface)) { + if (!is_buffer_shared(surface)) { switch (xenfb->depth) { case 8: if (bpp == 16) { @@ -648,10 +643,10 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h) xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n", __FUNCTION__, xenfb->depth, bpp); - dpy_gfx_update(xenfb->c.ds, x, y, w, h); + dpy_gfx_update(xenfb->c.con, x, y, w, h); } -#ifdef XENFB_TYPE_REFRESH_PERIOD +#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */ static int xenfb_queue_full(struct XenFB *xenfb) { struct xenfb_page *page = xenfb->c.page; @@ -703,13 +698,14 @@ static void xenfb_send_refresh_period(struct XenFB *xenfb, int period) static void xenfb_update(void *opaque) { struct XenFB *xenfb = opaque; + DisplaySurface *surface; int i; if (xenfb->c.xendev.be_state != XenbusStateConnected) return; if (xenfb->feature_update) { -#ifdef XENFB_TYPE_REFRESH_PERIOD +#if 0 /* XENFB_TYPE_REFRESH_PERIOD */ struct DisplayChangeListener *l; int period = 99999999; int idle = 1; @@ -753,21 +749,20 @@ static void xenfb_update(void *opaque) case 16: case 32: /* console.c supported depth -> buffer can be used directly */ - qemu_free_displaysurface(xenfb->c.ds); - xenfb->c.ds->surface = qemu_create_displaysurface_from + surface = qemu_create_displaysurface_from (xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset, false); break; default: /* we must convert stuff */ - qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height); + surface = qemu_create_displaysurface(xenfb->width, xenfb->height); break; } + dpy_gfx_replace_surface(xenfb->c.con, surface); xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n", xenfb->width, xenfb->height, xenfb->depth, - is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : ""); - dpy_gfx_resize(xenfb->c.ds); + is_buffer_shared(surface) ? " (shared)" : ""); xenfb->up_fullscreen = 1; } @@ -1009,16 +1004,16 @@ wait_more: /* vfb */ fb = container_of(xfb, struct XenFB, c.xendev); - fb->c.ds = graphic_console_init(xenfb_update, - xenfb_invalidate, - NULL, - NULL, - fb); + fb->c.con = graphic_console_init(xenfb_update, + xenfb_invalidate, + NULL, + NULL, + fb); fb->have_console = 1; /* vkbd */ in = container_of(xin, struct XenInput, c.xendev); - in->c.ds = fb->c.ds; + in->c.con = fb->c.con; /* retry ->init() */ xen_be_check_state(xin); diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c index 6c21b9668b..b2397f4a42 100644 --- a/hw/xilinx_spips.c +++ b/hw/xilinx_spips.c @@ -115,6 +115,19 @@ #define SNOOP_NONE 0xFE #define SNOOP_STRIPING 0 +typedef enum { + READ = 0x3, + FAST_READ = 0xb, + DOR = 0x3b, + QOR = 0x6b, + DIOR = 0xbb, + QIOR = 0xeb, + + PP = 0x2, + DPP = 0xa2, + QPP = 0x32, +} FlashCMD; + typedef struct { SysBusDevice busdev; MemoryRegion iomem; @@ -141,10 +154,15 @@ typedef struct { hwaddr lqspi_cached_addr; } XilinxSPIPS; +#define TYPE_XILINX_SPIPS "xilinx,spips" + +#define XILINX_SPIPS(obj) \ + OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS) + static inline int num_effective_busses(XilinxSPIPS *s) { - return (s->regs[R_LQSPI_STS] & LQSPI_CFG_SEP_BUS && - s->regs[R_LQSPI_STS] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; + return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS && + s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; } static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) @@ -197,7 +215,7 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s) static void xilinx_spips_reset(DeviceState *d) { - XilinxSPIPS *s = DO_UPCAST(XilinxSPIPS, busdev.qdev, d); + XilinxSPIPS *s = XILINX_SPIPS(d); int i; for (i = 0; i < R_MAX; i++) { @@ -251,15 +269,19 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) switch (s->snoop_state) { case (SNOOP_CHECKING): switch (tx) { /* new instruction code */ - case 0x0b: /* dual/quad output read DOR/QOR */ - case 0x6b: - s->snoop_state = 4; + case READ: /* 3 address bytes, no dummy bytes/cycles */ + case PP: + case DPP: + case QPP: + s->snoop_state = 3; break; - /* FIXME: these vary between vendor - set to spansion */ - case 0xbb: /* high performance dual read DIOR */ + case FAST_READ: /* 3 address bytes, 1 dummy byte */ + case DOR: + case QOR: + case DIOR: /* FIXME: these vary between vendor - set to spansion */ s->snoop_state = 4; break; - case 0xeb: /* high performance quad read QIOR */ + case QIOR: /* 3 address bytes, 2 dummy bytes */ s->snoop_state = 6; break; default: @@ -483,9 +505,10 @@ static const MemoryRegionOps lqspi_ops = { } }; -static int xilinx_spips_init(SysBusDevice *dev) +static void xilinx_spips_realize(DeviceState *dev, Error **errp) { - XilinxSPIPS *s = FROM_SYSBUS(typeof(*s), dev); + XilinxSPIPS *s = XILINX_SPIPS(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); int i; DB_PRINT("inited device model\n"); @@ -494,31 +517,29 @@ static int xilinx_spips_init(SysBusDevice *dev) for (i = 0; i < s->num_busses; ++i) { char bus_name[16]; snprintf(bus_name, 16, "spi%d", i); - s->spi[i] = ssi_create_bus(&dev->qdev, bus_name); + s->spi[i] = ssi_create_bus(dev, bus_name); } - s->cs_lines = g_new(qemu_irq, s->num_cs * s->num_busses); + s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]); ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); for (i = 0; i < s->num_cs * s->num_busses; ++i) { - sysbus_init_irq(dev, &s->cs_lines[i]); + sysbus_init_irq(sbd, &s->cs_lines[i]); } memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4); - sysbus_init_mmio(dev, &s->iomem); + sysbus_init_mmio(sbd, &s->iomem); memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi", (1 << LQSPI_ADDRESS_BITS) * 2); - sysbus_init_mmio(dev, &s->mmlqspi); + sysbus_init_mmio(sbd, &s->mmlqspi); s->irqline = -1; s->lqspi_cached_addr = ~0ULL; fifo8_create(&s->rx_fifo, RXFF_A); fifo8_create(&s->tx_fifo, TXFF_A); - - return 0; } static int xilinx_spips_post_load(void *opaque, int version_id) @@ -552,16 +573,15 @@ static Property xilinx_spips_properties[] = { static void xilinx_spips_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - sdc->init = xilinx_spips_init; + dc->realize = xilinx_spips_realize; dc->reset = xilinx_spips_reset; dc->props = xilinx_spips_properties; dc->vmsd = &vmstate_xilinx_spips; } static const TypeInfo xilinx_spips_info = { - .name = "xilinx,spips", + .name = TYPE_XILINX_SPIPS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(XilinxSPIPS), .class_init = xilinx_spips_class_init, diff --git a/include/qemu-common.h b/include/qemu-common.h index 5e137084b5..7754ee2fcc 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -442,4 +442,10 @@ int64_t pow2floor(int64_t value); int uleb128_encode_small(uint8_t *out, uint32_t n); int uleb128_decode_small(const uint8_t *in, uint32_t *n); +/* + * Hexdump a buffer to a file. An optional string prefix is added to every line + */ + +void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size); + #endif diff --git a/include/ui/console.h b/include/ui/console.h index a37cf65602..a234c72d2e 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -147,31 +147,43 @@ void cursor_set_mono(QEMUCursor *c, void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask); void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask); -struct DisplayChangeListener { - int idle; - uint64_t gui_timer_interval; +typedef struct DisplayChangeListenerOps { + const char *dpy_name; - void (*dpy_refresh)(struct DisplayState *s); + void (*dpy_refresh)(DisplayChangeListener *dcl); - void (*dpy_gfx_update)(struct DisplayState *s, int x, int y, int w, int h); - void (*dpy_gfx_resize)(struct DisplayState *s); - void (*dpy_gfx_setdata)(struct DisplayState *s); - void (*dpy_gfx_copy)(struct DisplayState *s, int src_x, int src_y, + void (*dpy_gfx_update)(DisplayChangeListener *dcl, + int x, int y, int w, int h); + void (*dpy_gfx_switch)(DisplayChangeListener *dcl, + struct DisplaySurface *new_surface); + void (*dpy_gfx_copy)(DisplayChangeListener *dcl, + int src_x, int src_y, int dst_x, int dst_y, int w, int h); - void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); - void (*dpy_text_resize)(struct DisplayState *s, int w, int h); - void (*dpy_text_update)(struct DisplayState *s, int x, int y, int w, int h); + void (*dpy_text_cursor)(DisplayChangeListener *dcl, + int x, int y); + void (*dpy_text_resize)(DisplayChangeListener *dcl, + int w, int h); + void (*dpy_text_update)(DisplayChangeListener *dcl, + int x, int y, int w, int h); - void (*dpy_mouse_set)(struct DisplayState *s, int x, int y, int on); - void (*dpy_cursor_define)(struct DisplayState *s, QEMUCursor *cursor); + void (*dpy_mouse_set)(DisplayChangeListener *dcl, + int x, int y, int on); + void (*dpy_cursor_define)(DisplayChangeListener *dcl, + QEMUCursor *cursor); +} DisplayChangeListenerOps; + +struct DisplayChangeListener { + int idle; + uint64_t gui_timer_interval; + const DisplayChangeListenerOps *ops; + DisplayState *ds; QLIST_ENTRY(DisplayChangeListener) next; }; struct DisplayState { struct DisplaySurface *surface; - void *opaque; struct QEMUTimer *gui_timer; bool have_gfx; bool have_text; @@ -189,11 +201,8 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, PixelFormat qemu_different_endianness_pixelformat(int bpp); PixelFormat qemu_default_pixelformat(int bpp); -DisplaySurface *qemu_create_displaysurface(DisplayState *ds, - int width, int height); -DisplaySurface *qemu_resize_displaysurface(DisplayState *ds, - int width, int height); -void qemu_free_displaysurface(DisplayState *ds); +DisplaySurface *qemu_create_displaysurface(int width, int height); +void qemu_free_displaysurface(DisplaySurface *surface); static inline int is_surface_bgr(DisplaySurface *surface) { @@ -210,208 +219,55 @@ static inline int is_buffer_shared(DisplaySurface *surface) void gui_setup_refresh(DisplayState *ds); -static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl) -{ - QLIST_INSERT_HEAD(&ds->listeners, dcl, next); - gui_setup_refresh(ds); - if (dcl->dpy_gfx_resize) { - dcl->dpy_gfx_resize(ds); - } -} - -static inline void unregister_displaychangelistener(DisplayState *ds, - DisplayChangeListener *dcl) -{ - QLIST_REMOVE(dcl, next); - gui_setup_refresh(ds); -} - -static inline void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h) -{ - struct DisplayChangeListener *dcl; - int width = pixman_image_get_width(s->surface->image); - int height = pixman_image_get_height(s->surface->image); - - x = MAX(x, 0); - y = MAX(y, 0); - x = MIN(x, width); - y = MIN(y, height); - w = MIN(w, width - x); - h = MIN(h, height - y); - - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_gfx_update) { - dcl->dpy_gfx_update(s, x, y, w, h); - } - } -} - -static inline void dpy_gfx_resize(DisplayState *s) +void register_displaychangelistener(DisplayState *ds, + DisplayChangeListener *dcl); +void unregister_displaychangelistener(DisplayChangeListener *dcl); + +void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); +void dpy_gfx_replace_surface(QemuConsole *con, + DisplaySurface *surface); +void dpy_refresh(DisplayState *s); +void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, + int dst_x, int dst_y, int w, int h); +void dpy_text_cursor(QemuConsole *con, int x, int y); +void dpy_text_update(QemuConsole *con, int x, int y, int w, int h); +void dpy_text_resize(QemuConsole *con, int w, int h); +void dpy_mouse_set(QemuConsole *con, int x, int y, int on); +void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor); +bool dpy_cursor_define_supported(QemuConsole *con); + +static inline int surface_stride(DisplaySurface *s) { - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_gfx_resize) { - dcl->dpy_gfx_resize(s); - } - } + return pixman_image_get_stride(s->image); } -static inline void dpy_gfx_setdata(DisplayState *s) +static inline void *surface_data(DisplaySurface *s) { - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_gfx_setdata) { - dcl->dpy_gfx_setdata(s); - } - } + return pixman_image_get_data(s->image); } -static inline void dpy_refresh(DisplayState *s) +static inline int surface_width(DisplaySurface *s) { - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_refresh) { - dcl->dpy_refresh(s); - } - } + return pixman_image_get_width(s->image); } -static inline void dpy_gfx_copy(struct DisplayState *s, int src_x, int src_y, - int dst_x, int dst_y, int w, int h) +static inline int surface_height(DisplaySurface *s) { - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_gfx_copy) { - dcl->dpy_gfx_copy(s, src_x, src_y, dst_x, dst_y, w, h); - } else { /* TODO */ - dcl->dpy_gfx_update(s, dst_x, dst_y, w, h); - } - } + return pixman_image_get_height(s->image); } -static inline void dpy_text_cursor(struct DisplayState *s, int x, int y) +static inline int surface_bits_per_pixel(DisplaySurface *s) { - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_text_cursor) { - dcl->dpy_text_cursor(s, x, y); - } - } -} - -static inline void dpy_text_update(DisplayState *s, int x, int y, int w, int h) -{ - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_text_update) { - dcl->dpy_text_update(s, x, y, w, h); - } - } -} - -static inline void dpy_text_resize(DisplayState *s, int w, int h) -{ - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_text_resize) { - dcl->dpy_text_resize(s, w, h); - } - } -} - -static inline void dpy_mouse_set(struct DisplayState *s, int x, int y, int on) -{ - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_mouse_set) { - dcl->dpy_mouse_set(s, x, y, on); - } - } -} - -static inline void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor) -{ - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_cursor_define) { - dcl->dpy_cursor_define(s, cursor); - } - } -} - -static inline bool dpy_cursor_define_supported(struct DisplayState *s) -{ - struct DisplayChangeListener *dcl; - QLIST_FOREACH(dcl, &s->listeners, next) { - if (dcl->dpy_cursor_define) { - return true; - } - } - return false; -} - -static inline int ds_get_linesize(DisplayState *ds) -{ - return pixman_image_get_stride(ds->surface->image); -} - -static inline uint8_t* ds_get_data(DisplayState *ds) -{ - return (void *)pixman_image_get_data(ds->surface->image); -} - -static inline int ds_get_width(DisplayState *ds) -{ - return pixman_image_get_width(ds->surface->image); -} - -static inline int ds_get_height(DisplayState *ds) -{ - return pixman_image_get_height(ds->surface->image); -} - -static inline int ds_get_bits_per_pixel(DisplayState *ds) -{ - int bits = PIXMAN_FORMAT_BPP(ds->surface->format); + int bits = PIXMAN_FORMAT_BPP(s->format); return bits; } -static inline int ds_get_bytes_per_pixel(DisplayState *ds) +static inline int surface_bytes_per_pixel(DisplaySurface *s) { - int bits = PIXMAN_FORMAT_BPP(ds->surface->format); + int bits = PIXMAN_FORMAT_BPP(s->format); return (bits + 7) / 8; } -static inline pixman_format_code_t ds_get_format(DisplayState *ds) -{ - return ds->surface->format; -} - -static inline pixman_image_t *ds_get_image(DisplayState *ds) -{ - return ds->surface->image; -} - -static inline int ds_get_depth(DisplayState *ds) -{ - return ds->surface->pf.depth; -} - -static inline int ds_get_rmask(DisplayState *ds) -{ - return ds->surface->pf.rmask; -} - -static inline int ds_get_gmask(DisplayState *ds) -{ - return ds->surface->pf.gmask; -} - -static inline int ds_get_bmask(DisplayState *ds) -{ - return ds->surface->pf.bmask; -} - #ifdef CONFIG_CURSES #include <curses.h> typedef chtype console_ch_t; @@ -431,11 +287,11 @@ typedef void (*vga_hw_screen_dump_ptr)(void *, const char *, bool cswitch, Error **errp); typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); -DisplayState *graphic_console_init(vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, - vga_hw_text_update_ptr text_update, - void *opaque); +QemuConsole *graphic_console_init(vga_hw_update_ptr update, + vga_hw_invalidate_ptr invalidate, + vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, + void *opaque); void vga_hw_update(void); void vga_hw_invalidate(void); @@ -446,9 +302,11 @@ int is_fixedsize_console(void); void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); void console_color_init(DisplayState *ds); -void qemu_console_resize(DisplayState *ds, int width, int height); -void qemu_console_copy(DisplayState *ds, int src_x, int src_y, +void qemu_console_resize(QemuConsole *con, int width, int height); +void qemu_console_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h); +DisplaySurface *qemu_console_surface(QemuConsole *con); +DisplayState *qemu_console_displaystate(QemuConsole *console); typedef CharDriverState *(VcHandler)(ChardevVC *vc); diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 46f9530fe3..7a20fc43ff 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -71,7 +71,9 @@ typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; struct SimpleSpiceDisplay { - DisplayState *ds; + QemuConsole *con; + DisplaySurface *ds; + DisplayChangeListener dcl; void *buf; int bufsize; QXLWorker *worker; @@ -112,11 +114,12 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); void qemu_spice_vm_change_state_handler(void *opaque, int running, RunState state); -void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds); +void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd); void qemu_spice_display_update(SimpleSpiceDisplay *ssd, int x, int y, int w, int h); -void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); +void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, + DisplaySurface *surface); void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd); diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index 472be35bbf..c7df595c9b 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -517,13 +517,8 @@ static inline void mipsdsp_rndrashift_short_acc(int64_t *p, acc = ((int64_t)env->active_tc.HI[ac] << 32) | ((int64_t)env->active_tc.LO[ac] & 0xFFFFFFFF); - if (shift == 0) { - p[0] = acc << 1; - p[1] = (acc >> 63) & 0x01; - } else { - p[0] = acc >> (shift - 1); - p[1] = 0; - } + p[0] = (shift == 0) ? (acc << 1) : (acc >> (shift - 1)); + p[1] = (acc >> 63) & 0x01; } /* 128 bits long. p[0] is LO, p[1] is HI */ @@ -3161,8 +3156,8 @@ target_ulong helper_extr_w(target_ulong ac, target_ulong shift, tempDL[1] += 1; } - if ((!(tempDL[1] == 0 && (tempDL[0] & MIPSDSP_LHI) == 0x00)) && - (!(tempDL[1] == 1 && (tempDL[0] & MIPSDSP_LHI) == MIPSDSP_LHI))) { + if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { set_DSPControl_overflow_flag(1, 23, env); } @@ -3187,8 +3182,8 @@ target_ulong helper_extr_r_w(target_ulong ac, target_ulong shift, tempDL[1] += 1; } - if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && - (tempDL[1] != 1 && (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { set_DSPControl_overflow_flag(1, 23, env); } @@ -3214,9 +3209,9 @@ target_ulong helper_extr_rs_w(target_ulong ac, target_ulong shift, } tempI = tempDL[0] >> 1; - if ((tempDL[1] != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && - (tempDL[1] != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { - temp64 = tempDL[1]; + if (((tempDL[1] & 0x01) != 0 || (tempDL[0] & MIPSDSP_LHI) != 0) && + ((tempDL[1] & 0x01) != 1 || (tempDL[0] & MIPSDSP_LHI) != MIPSDSP_LHI)) { + temp64 = tempDL[1] & 0x01; if (temp64 == 0) { tempI = 0x7FFFFFFF; } else { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 8f111ae732..644f484c48 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -315,8 +315,7 @@ void kvm_arch_post_run(CPUState *cpu, struct kvm_run *run) int kvm_arch_process_async_events(CPUState *cs) { - S390CPU *cpu = S390_CPU(cs); - return cpu->env.halted; + return cs->halted; } void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, diff --git a/tests/tcg/mips/mips32-dsp/extr_r_w.c b/tests/tcg/mips/mips32-dsp/extr_r_w.c index 02e022427a..489c1931b4 100644 --- a/tests/tcg/mips/mips32-dsp/extr_r_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_r_w.c @@ -67,5 +67,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0xFFFFFFFF; + acl = 0xFFFFFFFF; + result = 0; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_r.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_rs_w.c b/tests/tcg/mips/mips32-dsp/extr_rs_w.c index c3a22ee704..f9d2ed646f 100644 --- a/tests/tcg/mips/mips32-dsp/extr_rs_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_rs_w.c @@ -67,5 +67,51 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0x80000000; + acl = 0x00000000; + result = 0x80000000; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_rs.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 1); + assert(result == rt); + + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0xFFFFFFFF; + acl = 0xFFFFFFFF; + result = 0; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr_rs.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/extr_w.c b/tests/tcg/mips/mips32-dsp/extr_w.c index bd6b0b95c2..cf926146d5 100644 --- a/tests/tcg/mips/mips32-dsp/extr_w.c +++ b/tests/tcg/mips/mips32-dsp/extr_w.c @@ -67,5 +67,28 @@ int main() assert(dsp == 0); assert(result == rt); + /* Clear dspcontrol */ + dsp = 0; + __asm + ("wrdsp %0\n\t" + : + : "r"(dsp) + ); + + ach = 0xFFFFFFFF; + acl = 0xFFFFFFFF; + result = 0xFFFFFFFF; + __asm + ("mthi %2, $ac1\n\t" + "mtlo %3, $ac1\n\t" + "extr.w %0, $ac1, 0x1F\n\t" + "rddsp %1\n\t" + : "=r"(rt), "=r"(dsp) + : "r"(ach), "r"(acl) + ); + dsp = (dsp >> 23) & 0x01; + assert(dsp == 0); + assert(result == rt); + return 0; } diff --git a/trace-events b/trace-events index cd73b7f3ea..406fe5f408 100644 --- a/trace-events +++ b/trace-events @@ -958,8 +958,11 @@ dma_bdrv_cb(void *dbs, int ret) "dbs=%p ret=%d" dma_map_wait(void *dbs) "dbs=%p" # console.h -displaysurface_free(void *display_state, void *display_surface) "state=%p surface=%p" -displaysurface_resize(void *display_state, void *display_surface, int width, int height) "state=%p surface=%p %dx%d" +displaysurface_create(void *display_surface, int w, int h) "surface=%p, %dx%d" +displaysurface_create_from(void *display_surface, int w, int h, int bpp, int swap) "surface=%p, %dx%d, bpp %d, bswap %d" +displaysurface_free(void *display_surface) "surface=%p" +displaychangelistener_register(void *dcl, const char *name) "%p [ %s ]" +displaychangelistener_unregister(void *dcl, const char *name) "%p [ %s ]" # vga.c ppm_save(const char *filename, void *display_surface) "%s surface=%p" diff --git a/ui/cocoa.m b/ui/cocoa.m index ca42413b34..8e0eaa2601 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -264,8 +264,7 @@ static int cocoa_keycode_to_qemu(int keycode) BOOL isAbsoluteEnabled; BOOL isTabletEnabled; } -- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds; -- (void) updateDataOffset:(DisplayState *)ds; +- (void) switchSurface:(DisplaySurface *)surface; - (void) grabMouse; - (void) ungrabMouse; - (void) toggleFullScreen:(id)sender; @@ -400,19 +399,19 @@ QemuCocoaView *cocoaView; } } -- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds +- (void) switchSurface:(DisplaySurface *)surface { - COCOA_DEBUG("QemuCocoaView: resizeContent\n"); + COCOA_DEBUG("QemuCocoaView: switchSurface\n"); // update screenBuffer if (dataProviderRef) CGDataProviderRelease(dataProviderRef); //sync host window color space with guests - screen.bitsPerPixel = ds_get_bits_per_pixel(ds); - screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2; + screen.bitsPerPixel = surface_bits_per_pixel(surface); + screen.bitsPerComponent = surface_bytes_per_pixel(surface) * 2; - dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL); + dataProviderRef = CGDataProviderCreateWithData(NULL, surface_data(surface), w * 4 * h, NULL); // update windows if (isFullscreen) { @@ -430,20 +429,6 @@ QemuCocoaView *cocoaView; [self setFrame:NSMakeRect(cx, cy, cw, ch)]; } -- (void) updateDataOffset:(DisplayState *)ds -{ - COCOA_DEBUG("QemuCocoaView: UpdateDataOffset\n"); - - // update screenBuffer - if (dataProviderRef) { - CGDataProviderRelease(dataProviderRef); - } - - size_t size = ds_get_width(ds) * 4 * ds_get_height(ds); - dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), - size, NULL); -} - - (void) toggleFullScreen:(id)sender { COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n"); @@ -969,7 +954,8 @@ int main (int argc, const char * argv[]) { #pragma mark qemu -static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) +static void cocoa_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { COCOA_DEBUG("qemu_cocoa: cocoa_update\n"); @@ -986,14 +972,15 @@ static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) [cocoaView setNeedsDisplayInRect:rect]; } -static void cocoa_resize(DisplayState *ds) +static void cocoa_switch(DisplayChangeListener *dcl, + DisplaySurface *surface) { COCOA_DEBUG("qemu_cocoa: cocoa_resize\n"); - [cocoaView resizeContentToWidth:(int)(ds_get_width(ds)) height:(int)(ds_get_height(ds)) displayState:ds]; + [cocoaView switchSurface:surface]; } -static void cocoa_refresh(DisplayState *ds) +static void cocoa_refresh(DisplayChangeListener *dcl) { COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); @@ -1019,17 +1006,19 @@ static void cocoa_refresh(DisplayState *ds) vga_hw_update(); } -static void cocoa_setdata(DisplayState *ds) -{ - [cocoaView updateDataOffset:ds]; -} - static void cocoa_cleanup(void) { COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n"); g_free(dcl); } +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "cocoa", + .dpy_gfx_update = cocoa_update; + .dpy_gfx_switch = cocoa_switch; + .dpy_refresh = cocoa_refresh; +}; + void cocoa_display_init(DisplayState *ds, int full_screen) { COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); @@ -1037,12 +1026,8 @@ void cocoa_display_init(DisplayState *ds, int full_screen) dcl = g_malloc0(sizeof(DisplayChangeListener)); // register vga output callbacks - dcl->dpy_gfx_update = cocoa_update; - dcl->dpy_gfx_resize = cocoa_resize; - dcl->dpy_refresh = cocoa_refresh; - dcl->dpy_gfx_setdata = cocoa_setdata; - - register_displaychangelistener(ds, dcl); + dcl->ops = &dcl_ops; + register_displaychangelistener(ds, dcl); // register cleanup function atexit(cocoa_cleanup); diff --git a/ui/console.c b/ui/console.c index 27e87f8879..eb7a2bc1bf 100644 --- a/ui/console.c +++ b/ui/console.c @@ -208,51 +208,17 @@ void vga_hw_text_update(console_ch_t *chardata) active_console->hw_text_update(active_console->hw, chardata); } -/* convert a RGBA color to a color index usable in graphic primitives */ -static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba) -{ - unsigned int r, g, b, color; - - switch(ds_get_bits_per_pixel(ds)) { -#if 0 - case 8: - r = (rgba >> 16) & 0xff; - g = (rgba >> 8) & 0xff; - b = (rgba) & 0xff; - color = (rgb_to_index[r] * 6 * 6) + - (rgb_to_index[g] * 6) + - (rgb_to_index[b]); - break; -#endif - case 15: - r = (rgba >> 16) & 0xff; - g = (rgba >> 8) & 0xff; - b = (rgba) & 0xff; - color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); - break; - case 16: - r = (rgba >> 16) & 0xff; - g = (rgba >> 8) & 0xff; - b = (rgba) & 0xff; - color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); - break; - case 32: - default: - color = rgba; - break; - } - return color; -} - -static void vga_fill_rect (DisplayState *ds, - int posx, int posy, int width, int height, uint32_t color) +static void vga_fill_rect(QemuConsole *con, + int posx, int posy, int width, int height, + uint32_t color) { + DisplaySurface *surface = qemu_console_surface(con); uint8_t *d, *d1; int x, y, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d1 = ds_get_data(ds) + - ds_get_linesize(ds) * posy + bpp * posx; + bpp = surface_bytes_per_pixel(surface); + d1 = surface_data(surface) + + surface_stride(surface) * posy + bpp * posx; for (y = 0; y < height; y++) { d = d1; switch(bpp) { @@ -275,38 +241,40 @@ static void vga_fill_rect (DisplayState *ds, } break; } - d1 += ds_get_linesize(ds); + d1 += surface_stride(surface); } } /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */ -static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h) +static void vga_bitblt(QemuConsole *con, + int xs, int ys, int xd, int yd, int w, int h) { + DisplaySurface *surface = qemu_console_surface(con); const uint8_t *s; uint8_t *d; int wb, y, bpp; - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; + bpp = surface_bytes_per_pixel(surface); wb = w * bpp; if (yd <= ys) { - s = ds_get_data(ds) + - ds_get_linesize(ds) * ys + bpp * xs; - d = ds_get_data(ds) + - ds_get_linesize(ds) * yd + bpp * xd; + s = surface_data(surface) + + surface_stride(surface) * ys + bpp * xs; + d = surface_data(surface) + + surface_stride(surface) * yd + bpp * xd; for (y = 0; y < h; y++) { memmove(d, s, wb); - d += ds_get_linesize(ds); - s += ds_get_linesize(ds); + d += surface_stride(surface); + s += surface_stride(surface); } } else { - s = ds_get_data(ds) + - ds_get_linesize(ds) * (ys + h - 1) + bpp * xs; - d = ds_get_data(ds) + - ds_get_linesize(ds) * (yd + h - 1) + bpp * xd; + s = surface_data(surface) + + surface_stride(surface) * (ys + h - 1) + bpp * xs; + d = surface_data(surface) + + surface_stride(surface) * (yd + h - 1) + bpp * xd; for (y = 0; y < h; y++) { memmove(d, s, wb); - d -= ds_get_linesize(ds); - s -= ds_get_linesize(ds); + d -= surface_stride(surface); + s -= surface_stride(surface); } } } @@ -358,8 +326,6 @@ static const uint32_t dmask4[4] = { PAT(0xffffffff), }; -static uint32_t color_table[2][8]; - #ifndef CONFIG_CURSES enum color_names { COLOR_BLACK = 0, @@ -396,23 +362,6 @@ static const uint32_t color_table_rgb[2][8] = { } }; -static inline unsigned int col_expand(DisplayState *ds, unsigned int col) -{ - switch(ds_get_bits_per_pixel(ds)) { - case 8: - col |= col << 8; - col |= col << 16; - break; - case 15: - case 16: - col |= col << 16; - break; - default: - break; - } - - return col; -} #ifdef DEBUG_CONSOLE static void console_print_text_attributes(TextAttributes *t_attrib, char ch) { @@ -446,9 +395,10 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch) } #endif -static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, +static void vga_putcharxy(QemuConsole *s, int x, int y, int ch, TextAttributes *t_attrib) { + DisplaySurface *surface = qemu_console_surface(s); uint8_t *d; const uint8_t *font_ptr; unsigned int font_data, linesize, xorcol, bpp; @@ -461,20 +411,20 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, #endif if (t_attrib->invers) { - bgcol = color_table[t_attrib->bold][t_attrib->fgcol]; - fgcol = color_table[t_attrib->bold][t_attrib->bgcol]; + bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol]; + fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol]; } else { - fgcol = color_table[t_attrib->bold][t_attrib->fgcol]; - bgcol = color_table[t_attrib->bold][t_attrib->bgcol]; + fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol]; + bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol]; } - bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3; - d = ds_get_data(ds) + - ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; - linesize = ds_get_linesize(ds); + bpp = surface_bytes_per_pixel(surface); + d = surface_data(surface) + + surface_stride(surface) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH; + linesize = surface_stride(surface); font_ptr = vgafont16 + FONT_HEIGHT * ch; xorcol = bgcol ^ fgcol; - switch(ds_get_bits_per_pixel(ds)) { + switch (surface_bits_per_pixel(surface)) { case 8: for(i = 0; i < FONT_HEIGHT; i++) { font_data = *font_ptr++; @@ -579,19 +529,22 @@ static void update_xy(QemuConsole *s, int x, int y) TextCell *c; int y1, y2; - if (s == active_console) { - if (!ds_get_bits_per_pixel(s->ds)) { - text_update_xy(s, x, y); - return; - } + if (s != active_console) { + return; + } + if (s->ds->have_text) { + text_update_xy(s, x, y); + } + + if (s->ds->have_gfx) { y1 = (s->y_base + y) % s->total_height; y2 = y1 - s->y_displayed; if (y2 < 0) y2 += s->total_height; if (y2 < s->height) { c = &s->cells[y1 * s->width + x]; - vga_putcharxy(s->ds, x, y2, c->ch, + vga_putcharxy(s, x, y2, c->ch, &(c->t_attrib)); invalidate_xy(s, x, y2); } @@ -602,15 +555,17 @@ static void console_show_cursor(QemuConsole *s, int show) { TextCell *c; int y, y1; + int x = s->x; - if (s == active_console) { - int x = s->x; + if (s != active_console) { + return; + } - if (!ds_get_bits_per_pixel(s->ds)) { - s->cursor_invalidate = 1; - return; - } + if (s->ds->have_text) { + s->cursor_invalidate = 1; + } + if (s->ds->have_gfx) { if (x >= s->width) { x = s->width - 1; } @@ -623,9 +578,9 @@ static void console_show_cursor(QemuConsole *s, int show) if (show && s->cursor_visible_phase) { TextAttributes t_attrib = s->t_attrib_default; t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */ - vga_putcharxy(s->ds, x, y, c->ch, &t_attrib); + vga_putcharxy(s, x, y, c->ch, &t_attrib); } else { - vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); + vga_putcharxy(s, x, y, c->ch, &(c->t_attrib)); } invalidate_xy(s, x, y); } @@ -634,6 +589,7 @@ static void console_show_cursor(QemuConsole *s, int show) static void console_refresh(QemuConsole *s) { + DisplaySurface *surface = qemu_console_surface(s); TextCell *c; int x, y, y1; @@ -649,13 +605,13 @@ static void console_refresh(QemuConsole *s) } if (s->ds->have_gfx) { - vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds), - color_table[0][COLOR_BLACK]); + vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface), + color_table_rgb[0][COLOR_BLACK]); y1 = s->y_displayed; for (y = 0; y < s->height; y++) { c = s->cells + y1 * s->width; for (x = 0; x < s->width; x++) { - vga_putcharxy(s->ds, x, y, c->ch, + vga_putcharxy(s, x, y, c->ch, &(c->t_attrib)); c++; } @@ -664,7 +620,8 @@ static void console_refresh(QemuConsole *s) } } console_show_cursor(s, 1); - dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds)); + dpy_gfx_update(s, 0, 0, + surface_width(surface), surface_height(surface)); } } @@ -727,24 +684,25 @@ static void console_put_lf(QemuConsole *s) c++; } if (s == active_console && s->y_displayed == s->y_base) { - if (!ds_get_bits_per_pixel(s->ds)) { + if (s->ds->have_text) { s->text_x[0] = 0; s->text_y[0] = 0; s->text_x[1] = s->width - 1; s->text_y[1] = s->height - 1; - return; } - vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, - s->width * FONT_WIDTH, - (s->height - 1) * FONT_HEIGHT); - vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, - s->width * FONT_WIDTH, FONT_HEIGHT, - color_table[0][s->t_attrib_default.bgcol]); - s->update_x0 = 0; - s->update_y0 = 0; - s->update_x1 = s->width * FONT_WIDTH; - s->update_y1 = s->height * FONT_HEIGHT; + if (s->ds->have_gfx) { + vga_bitblt(s, 0, FONT_HEIGHT, 0, 0, + s->width * FONT_WIDTH, + (s->height - 1) * FONT_HEIGHT); + vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT, + s->width * FONT_WIDTH, FONT_HEIGHT, + color_table_rgb[0][s->t_attrib_default.bgcol]); + s->update_x0 = 0; + s->update_y0 = 0; + s->update_x1 = s->width * FONT_WIDTH; + s->update_y1 = s->height * FONT_HEIGHT; + } } } } @@ -1082,13 +1040,15 @@ static void console_putchar(QemuConsole *s, int ch) void console_select(unsigned int index) { + DisplaySurface *surface; QemuConsole *s; if (index >= MAX_CONSOLES) return; if (active_console) { - active_console->g_width = ds_get_width(active_console->ds); - active_console->g_height = ds_get_height(active_console->ds); + surface = qemu_console_surface(active_console); + active_console->g_width = surface_width(surface); + active_console->g_height = surface_height(surface); } s = consoles[index]; if (s) { @@ -1099,11 +1059,11 @@ void console_select(unsigned int index) } active_console = s; if (ds->have_gfx) { - ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height); - dpy_gfx_resize(ds); + surface = qemu_create_displaysurface(s->g_width, s->g_height); + dpy_gfx_replace_surface(s, surface); } if (ds->have_text) { - dpy_text_resize(ds, s->width, s->height); + dpy_text_resize(s, s->width, s->height); } if (s->cursor_timer) { qemu_mod_timer(s->cursor_timer, @@ -1128,7 +1088,7 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) } console_show_cursor(s, 1); if (s->ds->have_gfx && s->update_x0 < s->update_x1) { - dpy_gfx_update(s->ds, s->update_x0, s->update_y0, + dpy_gfx_update(s, s->update_x0, s->update_y0, s->update_x1 - s->update_x0, s->update_y1 - s->update_y0); } @@ -1216,9 +1176,11 @@ void kbd_put_keysym(int keysym) static void text_console_invalidate(void *opaque) { QemuConsole *s = (QemuConsole *) opaque; - if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) { - s->g_width = ds_get_width(s->ds); - s->g_height = ds_get_height(s->ds); + DisplaySurface *surface = qemu_console_surface(s); + + if (s->ds->have_text && s->console_type == TEXT_CONSOLE) { + s->g_width = surface_width(surface); + s->g_height = surface_height(surface); text_console_resize(s); } console_refresh(s); @@ -1238,7 +1200,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata) (s->cells[src].t_attrib.fgcol << 12) | (s->cells[src].t_attrib.bgcol << 8) | (s->cells[src].t_attrib.bold << 21)); - dpy_text_update(s->ds, s->text_x[0], s->text_y[0], + dpy_text_update(s, s->text_x[0], s->text_y[0], s->text_x[1] - s->text_x[0], i - s->text_y[0]); s->text_x[0] = s->width; s->text_y[0] = s->height; @@ -1246,23 +1208,11 @@ static void text_console_update(void *opaque, console_ch_t *chardata) s->text_y[1] = 0; } if (s->cursor_invalidate) { - dpy_text_cursor(s->ds, s->x, s->y); + dpy_text_cursor(s, s->x, s->y); s->cursor_invalidate = 0; } } -static QemuConsole *get_graphic_console(DisplayState *ds) -{ - int i; - QemuConsole *s; - for (i = 0; i < nb_consoles; i++) { - s = consoles[i]; - if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds) - return s; - } - return NULL; -} - static QemuConsole *new_console(DisplayState *ds, console_type_t console_type) { QemuConsole *s; @@ -1316,34 +1266,24 @@ static void qemu_alloc_display(DisplaySurface *surface, int width, int height, #endif } -DisplaySurface *qemu_create_displaysurface(DisplayState *ds, - int width, int height) +DisplaySurface *qemu_create_displaysurface(int width, int height) { DisplaySurface *surface = g_new0(DisplaySurface, 1); - int linesize = width * 4; + + trace_displaysurface_create(surface, width, height); qemu_alloc_display(surface, width, height, linesize, qemu_default_pixelformat(32), 0); return surface; } -DisplaySurface *qemu_resize_displaysurface(DisplayState *ds, - int width, int height) -{ - int linesize = width * 4; - - trace_displaysurface_resize(ds, ds->surface, width, height); - qemu_alloc_display(ds->surface, width, height, linesize, - qemu_default_pixelformat(32), 0); - return ds->surface; -} - DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp, int linesize, uint8_t *data, bool byteswap) { DisplaySurface *surface = g_new0(DisplaySurface, 1); + trace_displaysurface_create_from(surface, width, height, bpp, byteswap); if (byteswap) { surface->pf = qemu_different_endianness_pixelformat(bpp); } else { @@ -1364,14 +1304,162 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp, return surface; } -void qemu_free_displaysurface(DisplayState *ds) +void qemu_free_displaysurface(DisplaySurface *surface) { - trace_displaysurface_free(ds, ds->surface); - if (ds->surface == NULL) { + if (surface == NULL) { return; } - qemu_pixman_image_unref(ds->surface->image); - g_free(ds->surface); + trace_displaysurface_free(surface); + qemu_pixman_image_unref(surface->image); + g_free(surface); +} + +void register_displaychangelistener(DisplayState *ds, + DisplayChangeListener *dcl) +{ + trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); + dcl->ds = ds; + QLIST_INSERT_HEAD(&ds->listeners, dcl, next); + gui_setup_refresh(ds); + if (dcl->ops->dpy_gfx_switch) { + dcl->ops->dpy_gfx_switch(dcl, ds->surface); + } +} + +void unregister_displaychangelistener(DisplayChangeListener *dcl) +{ + DisplayState *ds = dcl->ds; + trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name); + QLIST_REMOVE(dcl, next); + gui_setup_refresh(ds); +} + +void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + int width = pixman_image_get_width(s->surface->image); + int height = pixman_image_get_height(s->surface->image); + + x = MAX(x, 0); + y = MAX(y, 0); + x = MIN(x, width); + y = MIN(y, height); + w = MIN(w, width - x); + h = MIN(h, height - y); + + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_gfx_update) { + dcl->ops->dpy_gfx_update(dcl, x, y, w, h); + } + } +} + +void dpy_gfx_replace_surface(QemuConsole *con, + DisplaySurface *surface) +{ + DisplayState *s = con->ds; + DisplaySurface *old_surface = s->surface; + struct DisplayChangeListener *dcl; + + s->surface = surface; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_gfx_switch) { + dcl->ops->dpy_gfx_switch(dcl, surface); + } + } + qemu_free_displaysurface(old_surface); +} + +void dpy_refresh(DisplayState *s) +{ + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_refresh) { + dcl->ops->dpy_refresh(dcl); + } + } +} + +void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y, + int dst_x, int dst_y, int w, int h) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_gfx_copy) { + dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h); + } else { /* TODO */ + dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h); + } + } +} + +void dpy_text_cursor(QemuConsole *con, int x, int y) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_text_cursor) { + dcl->ops->dpy_text_cursor(dcl, x, y); + } + } +} + +void dpy_text_update(QemuConsole *con, int x, int y, int w, int h) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_text_update) { + dcl->ops->dpy_text_update(dcl, x, y, w, h); + } + } +} + +void dpy_text_resize(QemuConsole *con, int w, int h) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_text_resize) { + dcl->ops->dpy_text_resize(dcl, w, h); + } + } +} + +void dpy_mouse_set(QemuConsole *con, int x, int y, int on) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_mouse_set) { + dcl->ops->dpy_mouse_set(dcl, x, y, on); + } + } +} + +void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_cursor_define) { + dcl->ops->dpy_cursor_define(dcl, cursor); + } + } +} + +bool dpy_cursor_define_supported(QemuConsole *con) +{ + DisplayState *s = con->ds; + struct DisplayChangeListener *dcl; + QLIST_FOREACH(dcl, &s->listeners, next) { + if (dcl->ops->dpy_cursor_define) { + return true; + } + } + return false; } static void dumb_display_init(void) @@ -1384,7 +1472,8 @@ static void dumb_display_init(void) width = active_console->g_width; height = active_console->g_height; } - ds->surface = qemu_create_displaysurface(ds, width, height); + ds->surface = qemu_create_displaysurface(width, height); + register_displaystate(ds); } @@ -1409,32 +1498,27 @@ DisplayState *get_displaystate(void) return display_state; } -DisplayState *graphic_console_init(vga_hw_update_ptr update, - vga_hw_invalidate_ptr invalidate, - vga_hw_screen_dump_ptr screen_dump, - vga_hw_text_update_ptr text_update, - void *opaque) +QemuConsole *graphic_console_init(vga_hw_update_ptr update, + vga_hw_invalidate_ptr invalidate, + vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, + void *opaque) { QemuConsole *s; DisplayState *ds; ds = (DisplayState *) g_malloc0(sizeof(DisplayState)); - ds->surface = qemu_create_displaysurface(ds, 640, 480); - s = new_console(ds, GRAPHIC_CONSOLE); - if (s == NULL) { - qemu_free_displaysurface(ds); - g_free(ds); - return NULL; - } s->hw_update = update; s->hw_invalidate = invalidate; s->hw_screen_dump = screen_dump; s->hw_text_update = text_update; s->hw = opaque; + ds->surface = qemu_create_displaysurface(640, 480); + register_displaystate(ds); - return ds; + return s; } int is_graphic_console(void) @@ -1447,17 +1531,6 @@ int is_fixedsize_console(void) return active_console && active_console->console_type != TEXT_CONSOLE; } -void console_color_init(DisplayState *ds) -{ - int i, j; - for (j = 0; j < 2; j++) { - for (i = 0; i < 8; i++) { - color_table[j][i] = col_expand(ds, - vga_get_color(ds, color_table_rgb[j][i])); - } - } -} - static void text_console_set_echo(CharDriverState *chr, bool echo) { QemuConsole *s = chr->opaque; @@ -1478,7 +1551,6 @@ static void text_console_update_cursor(void *opaque) static void text_console_do_init(CharDriverState *chr, DisplayState *ds) { QemuConsole *s; - static int color_inited; s = chr->opaque; @@ -1489,18 +1561,14 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds) s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s); s->ds = ds; - if (!color_inited) { - color_inited = 1; - console_color_init(s->ds); - } s->y_displayed = 0; s->y_base = 0; s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; if (s->console_type == TEXT_CONSOLE) { - s->g_width = ds_get_width(s->ds); - s->g_height = ds_get_height(s->ds); + s->g_width = surface_width(s->ds->surface); + s->g_height = surface_height(s->ds->surface); } s->cursor_timer = @@ -1600,27 +1668,35 @@ void text_consoles_set_display(DisplayState *ds) } } -void qemu_console_resize(DisplayState *ds, int width, int height) +void qemu_console_resize(QemuConsole *s, int width, int height) { - QemuConsole *s = get_graphic_console(ds); - if (!s) return; - s->g_width = width; s->g_height = height; if (is_graphic_console()) { - ds->surface = qemu_resize_displaysurface(ds, width, height); - dpy_gfx_resize(ds); + DisplaySurface *surface; + surface = qemu_create_displaysurface(width, height); + dpy_gfx_replace_surface(s, surface); } } -void qemu_console_copy(DisplayState *ds, int src_x, int src_y, +void qemu_console_copy(QemuConsole *con, int src_x, int src_y, int dst_x, int dst_y, int w, int h) { if (is_graphic_console()) { - dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h); + dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h); } } +DisplaySurface *qemu_console_surface(QemuConsole *console) +{ + return console->ds->surface; +} + +DisplayState *qemu_console_displaystate(QemuConsole *console) +{ + return console->ds; +} + PixelFormat qemu_different_endianness_pixelformat(int bpp) { PixelFormat pf; diff --git a/ui/curses.c b/ui/curses.c index d78e378440..ff82307361 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -35,12 +35,14 @@ #define FONT_HEIGHT 16 #define FONT_WIDTH 8 +static DisplayChangeListener *dcl; static console_ch_t screen[160 * 100]; static WINDOW *screenpad = NULL; static int width, height, gwidth, gheight, invalidate; static int px, py, sminx, sminy, smaxx, smaxy; -static void curses_update(DisplayState *ds, int x, int y, int w, int h) +static void curses_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { chtype *line; @@ -91,7 +93,8 @@ static void curses_calc_pad(void) } } -static void curses_resize(DisplayState *ds, int width, int height) +static void curses_resize(DisplayChangeListener *dcl, + int width, int height) { if (width == gwidth && height == gheight) { return; @@ -128,7 +131,8 @@ static void curses_winch_handler(int signum) #endif #endif -static void curses_cursor_position(DisplayState *ds, int x, int y) +static void curses_cursor_position(DisplayChangeListener *dcl, + int x, int y) { if (x >= 0) { x = sminx + x - px; @@ -154,7 +158,7 @@ static void curses_cursor_position(DisplayState *ds, int x, int y) static kbd_layout_t *kbd_layout = NULL; -static void curses_refresh(DisplayState *ds) +static void curses_refresh(DisplayChangeListener *dcl) { int chr, nextchr, keysym, keycode, keycode_alt; @@ -187,7 +191,7 @@ static void curses_refresh(DisplayState *ds) clear(); refresh(); curses_calc_pad(); - curses_update(ds, 0, 0, width, height); + curses_update(dcl, 0, 0, width, height); continue; } #endif @@ -323,9 +327,16 @@ static void curses_keyboard_setup(void) } } +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "curses", + .dpy_text_update = curses_update, + .dpy_text_resize = curses_resize, + .dpy_refresh = curses_refresh, + .dpy_text_cursor = curses_cursor_position, +}; + void curses_display_init(DisplayState *ds, int full_screen) { - DisplayChangeListener *dcl; #ifndef _WIN32 if (!isatty(1)) { fprintf(stderr, "We need a terminal output\n"); @@ -346,10 +357,7 @@ void curses_display_init(DisplayState *ds, int full_screen) #endif dcl = (DisplayChangeListener *) g_malloc0(sizeof(DisplayChangeListener)); - dcl->dpy_text_update = curses_update; - dcl->dpy_text_resize = curses_resize; - dcl->dpy_refresh = curses_refresh; - dcl->dpy_text_cursor = curses_cursor_position; + dcl->ops = &dcl_ops; register_displaychangelistener(ds, dcl); invalidate = 1; @@ -143,7 +143,7 @@ typedef struct GtkDisplayState GtkWidget *drawing_area; cairo_surface_t *surface; DisplayChangeListener dcl; - DisplayState *ds; + DisplaySurface *ds; int button_mask; int last_x; int last_y; @@ -225,11 +225,50 @@ static void gd_update_caption(GtkDisplayState *s) g_free(title); } +static void gd_update_windowsize(GtkDisplayState *s) +{ + if (!s->full_screen) { + GtkRequisition req; + double sx, sy; + + if (s->free_scale) { + sx = s->scale_x; + sy = s->scale_y; + + s->scale_y = 1.0; + s->scale_x = 1.0; + } else { + sx = 1.0; + sy = 1.0; + } + + gtk_widget_set_size_request(s->drawing_area, + surface_width(s->ds) * s->scale_x, + surface_height(s->ds) * s->scale_y); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_widget_get_preferred_size(s->vbox, NULL, &req); +#else + gtk_widget_size_request(s->vbox, &req); +#endif + + gtk_window_resize(GTK_WINDOW(s->window), + req.width * sx, req.height * sy); + } +} + +static void gd_update_full_redraw(GtkDisplayState *s) +{ + int ww, wh; + gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); + gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh); +} + /** DisplayState Callbacks **/ -static void gd_update(DisplayState *ds, int x, int y, int w, int h) +static void gd_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { - GtkDisplayState *s = ds->opaque; + GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl); int x1, x2, y1, y2; int mx, my; int fbw, fbh; @@ -243,8 +282,8 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h) x2 = ceil(x * s->scale_x + w * s->scale_x); y2 = ceil(y * s->scale_y + h * s->scale_y); - fbw = ds_get_width(s->ds) * s->scale_x; - fbh = ds_get_height(s->ds) * s->scale_y; + fbw = surface_width(s->ds) * s->scale_x; + fbh = surface_height(s->ds) * s->scale_y; gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); @@ -259,25 +298,33 @@ static void gd_update(DisplayState *ds, int x, int y, int w, int h) gtk_widget_queue_draw_area(s->drawing_area, mx + x1, my + y1, (x2 - x1), (y2 - y1)); } -static void gd_refresh(DisplayState *ds) +static void gd_refresh(DisplayChangeListener *dcl) { vga_hw_update(); } -static void gd_resize(DisplayState *ds) +static void gd_switch(DisplayChangeListener *dcl, + DisplaySurface *surface) { - GtkDisplayState *s = ds->opaque; + GtkDisplayState *s = container_of(dcl, GtkDisplayState, dcl); cairo_format_t kind; + bool resized = true; int stride; DPRINTF("resize(width=%d, height=%d)\n", - ds_get_width(ds), ds_get_height(ds)); + surface_width(surface), surface_height(surface)); if (s->surface) { cairo_surface_destroy(s->surface); } - switch (ds->surface->pf.bits_per_pixel) { + if (s->ds && + surface_width(s->ds) == surface_width(surface) && + surface_height(s->ds) == surface_height(surface)) { + resized = false; + } + s->ds = surface; + switch (surface_bits_per_pixel(surface)) { case 8: kind = CAIRO_FORMAT_A8; break; @@ -292,41 +339,19 @@ static void gd_resize(DisplayState *ds) break; } - stride = cairo_format_stride_for_width(kind, ds_get_width(ds)); - g_assert(ds_get_linesize(ds) == stride); + stride = cairo_format_stride_for_width(kind, surface_width(surface)); + g_assert(surface_stride(surface) == stride); - s->surface = cairo_image_surface_create_for_data(ds_get_data(ds), + s->surface = cairo_image_surface_create_for_data(surface_data(surface), kind, - ds_get_width(ds), - ds_get_height(ds), - ds_get_linesize(ds)); - - if (!s->full_screen) { - GtkRequisition req; - double sx, sy; - - if (s->free_scale) { - sx = s->scale_x; - sy = s->scale_y; - - s->scale_y = 1.0; - s->scale_x = 1.0; - } else { - sx = 1.0; - sy = 1.0; - } - - gtk_widget_set_size_request(s->drawing_area, - ds_get_width(ds) * s->scale_x, - ds_get_height(ds) * s->scale_y); -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_widget_get_preferred_size(s->vbox, NULL, &req); -#else - gtk_widget_size_request(s->vbox, &req); -#endif + surface_width(surface), + surface_height(surface), + surface_stride(surface)); - gtk_window_resize(GTK_WINDOW(s->window), - req.width * sx, req.height * sy); + if (resized) { + gd_update_windowsize(s); + } else { + gd_update_full_redraw(s); } } @@ -382,7 +407,7 @@ static gboolean gd_window_close(GtkWidget *widget, GdkEvent *event, GtkDisplayState *s = opaque; if (!no_quit) { - unregister_displaychangelistener(s->ds, &s->dcl); + unregister_displaychangelistener(&s->dcl); qmp_quit(NULL); return FALSE; } @@ -401,8 +426,8 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) return FALSE; } - fbw = ds_get_width(s->ds); - fbh = ds_get_height(s->ds); + fbw = surface_width(s->ds); + fbh = surface_height(s->ds); gdk_drawable_get_size(gtk_widget_get_window(widget), &ww, &wh); @@ -480,8 +505,8 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, int fbh, fbw; int ww, wh; - fbw = ds_get_width(s->ds) * s->scale_x; - fbh = ds_get_height(s->ds) * s->scale_y; + fbw = surface_width(s->ds) * s->scale_x; + fbh = surface_height(s->ds) * s->scale_y; gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); @@ -497,14 +522,14 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, y = (motion->y - my) / s->scale_y; if (x < 0 || y < 0 || - x >= ds_get_width(s->ds) || - y >= ds_get_height(s->ds)) { + x >= surface_width(s->ds) || + y >= surface_height(s->ds)) { return TRUE; } if (kbd_mouse_is_absolute()) { - dx = x * 0x7FFF / (ds_get_width(s->ds) - 1); - dy = y * 0x7FFF / (ds_get_height(s->ds) - 1); + dx = x * 0x7FFF / (surface_width(s->ds) - 1); + dy = y * 0x7FFF / (surface_height(s->ds) - 1); } else if (s->last_x == -1 || s->last_y == -1) { dx = 0; dy = 0; @@ -585,8 +610,8 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, } if (kbd_mouse_is_absolute()) { - dx = s->last_x * 0x7FFF / (ds_get_width(s->ds) - 1); - dy = s->last_y * 0x7FFF / (ds_get_height(s->ds) - 1); + dx = s->last_x * 0x7FFF / (surface_width(s->ds) - 1); + dy = s->last_y * 0x7FFF / (surface_height(s->ds) - 1); } else { dx = 0; dy = 0; @@ -715,7 +740,8 @@ static void gd_menu_full_screen(GtkMenuItem *item, void *opaque) gd_menu_show_tabs(GTK_MENU_ITEM(s->show_tabs_item), s); gtk_widget_set_size_request(s->menu_bar, -1, -1); gtk_widget_set_size_request(s->drawing_area, - ds_get_width(s->ds), ds_get_height(s->ds)); + surface_width(s->ds), + surface_height(s->ds)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item), FALSE); s->full_screen = FALSE; s->scale_x = 1.0; @@ -735,7 +761,7 @@ static void gd_menu_zoom_in(GtkMenuItem *item, void *opaque) s->scale_x += .25; s->scale_y += .25; - gd_resize(s->ds); + gd_update_windowsize(s); } static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque) @@ -751,7 +777,7 @@ static void gd_menu_zoom_out(GtkMenuItem *item, void *opaque) s->scale_x = MAX(s->scale_x, .25); s->scale_y = MAX(s->scale_y, .25); - gd_resize(s->ds); + gd_update_windowsize(s); } static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque) @@ -761,13 +787,12 @@ static void gd_menu_zoom_fixed(GtkMenuItem *item, void *opaque) s->scale_x = 1.0; s->scale_y = 1.0; - gd_resize(s->ds); + gd_update_windowsize(s); } static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) { GtkDisplayState *s = opaque; - int ww, wh; if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->zoom_fit_item))) { s->free_scale = TRUE; @@ -775,10 +800,8 @@ static void gd_menu_zoom_fit(GtkMenuItem *item, void *opaque) s->free_scale = FALSE; } - gd_resize(s->ds); - - gdk_drawable_get_size(gtk_widget_get_window(s->drawing_area), &ww, &wh); - gtk_widget_queue_draw_area(s->drawing_area, 0, 0, ww, wh); + gd_update_windowsize(s); + gd_update_full_redraw(s); } static void gd_grab_keyboard(GtkDisplayState *s) @@ -1281,17 +1304,20 @@ static void gd_create_menus(GtkDisplayState *s) gtk_menu_shell_append(GTK_MENU_SHELL(s->menu_bar), s->view_menu_item); } +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "gtk", + .dpy_gfx_update = gd_update, + .dpy_gfx_switch = gd_switch, + .dpy_refresh = gd_refresh, +}; + void gtk_display_init(DisplayState *ds) { GtkDisplayState *s = g_malloc0(sizeof(*s)); gtk_init(NULL, NULL); - ds->opaque = s; - s->ds = ds; - s->dcl.dpy_gfx_update = gd_update; - s->dcl.dpy_gfx_resize = gd_resize; - s->dcl.dpy_refresh = gd_refresh; + s->dcl.ops = &dcl_ops; s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); #if GTK_CHECK_VERSION(3, 2, 0) @@ -35,6 +35,7 @@ #include "sdl_zoom.h" static DisplayChangeListener *dcl; +static DisplaySurface *surface; static SDL_Surface *real_screen; static SDL_Surface *guest_screen = NULL; static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ @@ -59,7 +60,8 @@ static SDL_PixelFormat host_format; static int scaling_active = 0; static Notifier mouse_mode_notifier; -static void sdl_update(DisplayState *ds, int x, int y, int w, int h) +static void sdl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); SDL_Rect rec; @@ -81,16 +83,6 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h) SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h); } -static void sdl_setdata(DisplayState *ds) -{ - if (guest_screen != NULL) SDL_FreeSurface(guest_screen); - - guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds), - ds_get_bits_per_pixel(ds), ds_get_linesize(ds), - ds->surface->pf.rmask, ds->surface->pf.gmask, - ds->surface->pf.bmask, ds->surface->pf.amask); -} - static void do_sdl_resize(int width, int height, int bpp) { int flags; @@ -114,15 +106,32 @@ static void do_sdl_resize(int width, int height, int bpp) } } -static void sdl_resize(DisplayState *ds) +static void sdl_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface) { + + /* temporary hack: allows to call sdl_switch to handle scaling changes */ + if (new_surface) { + surface = new_surface; + } + if (!scaling_active) { - do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0); - } else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds)) { + do_sdl_resize(surface_width(surface), surface_height(surface), 0); + } else if (real_screen->format->BitsPerPixel != + surface_bits_per_pixel(surface)) { do_sdl_resize(real_screen->w, real_screen->h, - ds_get_bits_per_pixel(ds)); + surface_bits_per_pixel(surface)); + } + + if (guest_screen != NULL) { + SDL_FreeSurface(guest_screen); } - sdl_setdata(ds); + guest_screen = SDL_CreateRGBSurfaceFrom + (surface_data(surface), + surface_width(surface), surface_height(surface), + surface_bits_per_pixel(surface), surface_stride(surface), + surface->pf.rmask, surface->pf.gmask, + surface->pf.bmask, surface->pf.amask); } /* generic keyboard conversion */ @@ -445,7 +454,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state kbd_mouse_event(dx, dy, dz, buttons); } -static void sdl_scale(DisplayState *ds, int width, int height) +static void sdl_scale(int width, int height) { int bpp = real_screen->format->BitsPerPixel; @@ -454,32 +463,30 @@ static void sdl_scale(DisplayState *ds, int width, int height) } do_sdl_resize(width, height, bpp); scaling_active = 1; - if (!is_buffer_shared(ds->surface)) { - ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), - ds_get_height(ds)); - dpy_gfx_resize(ds); - } } -static void toggle_full_screen(DisplayState *ds) +static void toggle_full_screen(void) { + int width = surface_width(surface); + int height = surface_height(surface); + int bpp = surface_bits_per_pixel(surface); + gui_fullscreen = !gui_fullscreen; if (gui_fullscreen) { gui_saved_width = real_screen->w; gui_saved_height = real_screen->h; gui_saved_scaling = scaling_active; - do_sdl_resize(ds_get_width(ds), ds_get_height(ds), - ds_get_bits_per_pixel(ds)); + do_sdl_resize(width, height, bpp); scaling_active = 0; gui_saved_grab = gui_grab; sdl_grab_start(); } else { if (gui_saved_scaling) { - sdl_scale(ds, gui_saved_width, gui_saved_height); + sdl_scale(gui_saved_width, gui_saved_height); } else { - do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0); + do_sdl_resize(width, height, 0); } if (!gui_saved_grab || !is_graphic_console()) { sdl_grab_end(); @@ -489,7 +496,7 @@ static void toggle_full_screen(DisplayState *ds) vga_hw_update(); } -static void handle_keydown(DisplayState *ds, SDL_Event *ev) +static void handle_keydown(SDL_Event *ev) { int mod_state; int keycode; @@ -508,13 +515,13 @@ static void handle_keydown(DisplayState *ds, SDL_Event *ev) keycode = sdl_keyevent_to_keycode(&ev->key); switch (keycode) { case 0x21: /* 'f' key on US keyboard */ - toggle_full_screen(ds); + toggle_full_screen(); gui_keysym = 1; break; case 0x16: /* 'u' key on US keyboard */ if (scaling_active) { scaling_active = 0; - sdl_resize(ds); + sdl_switch(dcl, NULL); vga_hw_invalidate(); vga_hw_update(); } @@ -545,9 +552,10 @@ static void handle_keydown(DisplayState *ds, SDL_Event *ev) if (!gui_fullscreen) { int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50), 160); - int height = (ds_get_height(ds) * width) / ds_get_width(ds); + int height = (surface_height(surface) * width) / + surface_width(surface); - sdl_scale(ds, width, height); + sdl_scale(width, height); vga_hw_invalidate(); vga_hw_update(); gui_keysym = 1; @@ -634,7 +642,7 @@ static void handle_keydown(DisplayState *ds, SDL_Event *ev) } } -static void handle_keyup(DisplayState *ds, SDL_Event *ev) +static void handle_keyup(SDL_Event *ev) { int mod_state; @@ -666,7 +674,7 @@ static void handle_keyup(DisplayState *ds, SDL_Event *ev) } } -static void handle_mousemotion(DisplayState *ds, SDL_Event *ev) +static void handle_mousemotion(SDL_Event *ev) { int max_x, max_y; @@ -690,7 +698,7 @@ static void handle_mousemotion(DisplayState *ds, SDL_Event *ev) } } -static void handle_mousebutton(DisplayState *ds, SDL_Event *ev) +static void handle_mousebutton(SDL_Event *ev) { int buttonstate = SDL_GetMouseState(NULL, NULL); SDL_MouseButtonEvent *bev; @@ -726,7 +734,7 @@ static void handle_mousebutton(DisplayState *ds, SDL_Event *ev) } } -static void handle_activation(DisplayState *ds, SDL_Event *ev) +static void handle_activation(SDL_Event *ev) { #ifdef _WIN32 /* Disable grab if the window no longer has the focus @@ -753,7 +761,7 @@ static void handle_activation(DisplayState *ds, SDL_Event *ev) } } -static void sdl_refresh(DisplayState *ds) +static void sdl_refresh(DisplayChangeListener *dcl) { SDL_Event ev1, *ev = &ev1; @@ -768,13 +776,13 @@ static void sdl_refresh(DisplayState *ds) while (SDL_PollEvent(ev)) { switch (ev->type) { case SDL_VIDEOEXPOSE: - sdl_update(ds, 0, 0, real_screen->w, real_screen->h); + sdl_update(dcl, 0, 0, real_screen->w, real_screen->h); break; case SDL_KEYDOWN: - handle_keydown(ds, ev); + handle_keydown(ev); break; case SDL_KEYUP: - handle_keyup(ds, ev); + handle_keyup(ev); break; case SDL_QUIT: if (!no_quit) { @@ -783,17 +791,17 @@ static void sdl_refresh(DisplayState *ds) } break; case SDL_MOUSEMOTION: - handle_mousemotion(ds, ev); + handle_mousemotion(ev); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - handle_mousebutton(ds, ev); + handle_mousebutton(ev); break; case SDL_ACTIVEEVENT: - handle_activation(ds, ev); + handle_activation(ev); break; case SDL_VIDEORESIZE: - sdl_scale(ds, ev->resize.w, ev->resize.h); + sdl_scale(ev->resize.w, ev->resize.h); vga_hw_invalidate(); vga_hw_update(); break; @@ -803,7 +811,8 @@ static void sdl_refresh(DisplayState *ds) } } -static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on) +static void sdl_mouse_warp(DisplayChangeListener *dcl, + int x, int y, int on) { if (on) { if (!guest_cursor) @@ -819,7 +828,8 @@ static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on) guest_x = x, guest_y = y; } -static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c) +static void sdl_mouse_define(DisplayChangeListener *dcl, + QEMUCursor *c) { uint8_t *image, *mask; int bpl; @@ -849,6 +859,15 @@ static void sdl_cleanup(void) SDL_QuitSubSystem(SDL_INIT_VIDEO); } +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "sdl", + .dpy_gfx_update = sdl_update, + .dpy_gfx_switch = sdl_switch, + .dpy_refresh = sdl_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, +}; + void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { int flags; @@ -917,12 +936,7 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) } dcl = g_malloc0(sizeof(DisplayChangeListener)); - dcl->dpy_gfx_update = sdl_update; - dcl->dpy_gfx_resize = sdl_resize; - dcl->dpy_refresh = sdl_refresh; - dcl->dpy_gfx_setdata = sdl_setdata; - dcl->dpy_mouse_set = sdl_mouse_warp; - dcl->dpy_cursor_define = sdl_mouse_define; + dcl->ops = &dcl_ops; register_displaychangelistener(ds, dcl); mouse_mode_notifier.notify = sdl_mouse_mode_change; diff --git a/ui/spice-display.c b/ui/spice-display.c index dc7e58d0ed..eaab19d9bd 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -214,10 +214,10 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) { static const int blksize = 32; - int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize; + int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize; int dirty_top[blocks]; int y, yoff, x, xoff, blk, bw; - int bpp = ds_get_bytes_per_pixel(ssd->ds); + int bpp = surface_bytes_per_pixel(ssd->ds); uint8_t *guest, *mirror; if (qemu_spice_rect_is_empty(&ssd->dirty)) { @@ -225,19 +225,19 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) }; if (ssd->surface == NULL) { - ssd->surface = pixman_image_ref(ds_get_image(ssd->ds)); - ssd->mirror = qemu_pixman_mirror_create(ds_get_format(ssd->ds), - ds_get_image(ssd->ds)); + ssd->surface = pixman_image_ref(ssd->ds->image); + ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, + ssd->ds->image); } for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } - guest = ds_get_data(ssd->ds); + guest = surface_data(ssd->ds); mirror = (void *)pixman_image_get_data(ssd->mirror); for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { - yoff = y * ds_get_linesize(ssd->ds); + yoff = y * surface_stride(ssd->ds); for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { xoff = x * bpp; blk = x / blksize; @@ -312,11 +312,11 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) memset(&surface, 0, sizeof(surface)); dprint(1, "%s: %dx%d\n", __FUNCTION__, - ds_get_width(ssd->ds), ds_get_height(ssd->ds)); + surface_width(ssd->ds), surface_height(ssd->ds)); surface.format = SPICE_SURFACE_FMT_32_xRGB; - surface.width = ds_get_width(ssd->ds); - surface.height = ds_get_height(ssd->ds); + surface.width = surface_width(ssd->ds); + surface.height = surface_height(ssd->ds); surface.stride = -surface.width * 4; surface.mouse_mode = true; surface.flags = 0; @@ -334,9 +334,8 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); } -void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) +void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd) { - ssd->ds = ds; qemu_mutex_init(&ssd->lock); QTAILQ_INIT(&ssd->updates); ssd->mouse_x = -1; @@ -367,7 +366,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, qemu_spice_rect_union(&ssd->dirty, &update_area); } -void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) +void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, + DisplaySurface *surface) { SimpleSpiceUpdate *update; @@ -382,6 +382,7 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) } qemu_mutex_lock(&ssd->lock); + ssd->ds = surface; while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { QTAILQ_REMOVE(&ssd->updates, update, next); qemu_spice_destroy_update(ssd, update); @@ -397,12 +398,14 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) { if (ssd->cursor) { - dpy_cursor_define(ssd->ds, ssd->cursor); + assert(ssd->con); + dpy_cursor_define(ssd->con, ssd->cursor); cursor_put(ssd->cursor); ssd->cursor = NULL; } if (ssd->mouse_x != -1 && ssd->mouse_y != -1) { - dpy_mouse_set(ssd->ds, ssd->mouse_x, ssd->mouse_y, 1); + assert(ssd->con); + dpy_mouse_set(ssd->con, ssd->mouse_x, ssd->mouse_y, 1); ssd->mouse_x = -1; ssd->mouse_y = -1; } @@ -414,7 +417,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) vga_hw_update(); qemu_mutex_lock(&ssd->lock); - if (QTAILQ_EMPTY(&ssd->updates)) { + if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) { qemu_spice_create_update(ssd); ssd->notify++; } @@ -581,39 +584,47 @@ static const QXLInterface dpy_interface = { .client_monitors_config = interface_client_monitors_config, }; -static SimpleSpiceDisplay sdpy; - -static void display_update(struct DisplayState *ds, int x, int y, int w, int h) +static void display_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { - qemu_spice_display_update(&sdpy, x, y, w, h); + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + qemu_spice_display_update(ssd, x, y, w, h); } -static void display_resize(struct DisplayState *ds) +static void display_switch(DisplayChangeListener *dcl, + struct DisplaySurface *surface) { - qemu_spice_display_resize(&sdpy); + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + qemu_spice_display_switch(ssd, surface); } -static void display_refresh(struct DisplayState *ds) +static void display_refresh(DisplayChangeListener *dcl) { - qemu_spice_display_refresh(&sdpy); + SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); + qemu_spice_display_refresh(ssd); } -static DisplayChangeListener display_listener = { +static const DisplayChangeListenerOps display_listener_ops = { + .dpy_name = "spice", .dpy_gfx_update = display_update, - .dpy_gfx_resize = display_resize, - .dpy_refresh = display_refresh, + .dpy_gfx_switch = display_switch, + .dpy_refresh = display_refresh, }; void qemu_spice_display_init(DisplayState *ds) { - assert(sdpy.ds == NULL); - qemu_spice_display_init_common(&sdpy, ds); + SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1); + + qemu_spice_display_init_common(ssd); + + ssd->qxl.base.sif = &dpy_interface.base; + qemu_spice_add_interface(&ssd->qxl.base); + assert(ssd->worker); - sdpy.qxl.base.sif = &dpy_interface.base; - qemu_spice_add_interface(&sdpy.qxl.base); - assert(sdpy.worker); + qemu_spice_create_host_memslot(ssd); - qemu_spice_create_host_memslot(&sdpy); - qemu_spice_create_host_primary(&sdpy); - register_displaychangelistener(ds, &display_listener); + ssd->dcl.ops = &display_listener_ops; + register_displaychangelistener(ds, &ssd->dcl); + + qemu_spice_create_host_primary(ssd); } diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 4ddea7d4f5..e6966aebc3 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -123,7 +123,7 @@ static bool tight_can_send_png_rect(VncState *vs, int w, int h) return false; } - if (ds_get_bytes_per_pixel(vs->ds) == 1 || + if (surface_bytes_per_pixel(vs->vd->ds) == 1 || vs->client_pf.bytes_per_pixel == 1) { return false; } @@ -301,7 +301,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) return 0; } - if (ds_get_bytes_per_pixel(vs->ds) == 1 || + if (surface_bytes_per_pixel(vs->vd->ds) == 1 || vs->client_pf.bytes_per_pixel == 1 || w < VNC_TIGHT_DETECT_MIN_WIDTH || h < VNC_TIGHT_DETECT_MIN_HEIGHT) { return 0; @@ -1184,8 +1184,9 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) uint8_t *buf; int dy; - if (ds_get_bytes_per_pixel(vs->ds) == 1) + if (surface_bytes_per_pixel(vs->vd->ds) == 1) { return send_full_color_rect(vs, x, y, w, h); + } buffer_reserve(&vs->tight.jpeg, 2048); diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index 0bfc0c5485..2d3fce8155 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -183,7 +183,6 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local) { local->vnc_encoding = orig->vnc_encoding; local->features = orig->features; - local->ds = orig->ds; local->vd = orig->vd; local->lossy_rect = orig->lossy_rect; local->write_pixels = orig->write_pixels; @@ -44,7 +44,6 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 }; #include "d3des.h" static VncDisplay *vnc_display; /* needed for info vnc */ -static DisplayChangeListener *dcl; static int vnc_cursor_define(VncState *vs); static void vnc_release_modifiers(VncState *vs); @@ -430,13 +429,14 @@ static void framebuffer_update_request(VncState *vs, int incremental, static void vnc_refresh(void *opaque); static int vnc_refresh_server_surface(VncDisplay *vd); -static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) +static void vnc_dpy_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) { int i; - VncDisplay *vd = ds->opaque; + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); struct VncSurface *s = &vd->guest; - int width = ds_get_width(ds); - int height = ds_get_height(ds); + int width = surface_width(vd->ds); + int height = surface_height(vd->ds); h += y; @@ -518,17 +518,17 @@ void buffer_advance(Buffer *buf, size_t len) static void vnc_desktop_resize(VncState *vs) { - DisplayState *ds = vs->ds; + DisplaySurface *ds = vs->vd->ds; if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { return; } - if (vs->client_width == ds_get_width(ds) && - vs->client_height == ds_get_height(ds)) { + if (vs->client_width == surface_width(ds) && + vs->client_height == surface_height(ds)) { return; } - vs->client_width = ds_get_width(ds); - vs->client_height = ds_get_height(ds); + vs->client_width = surface_width(ds); + vs->client_height = surface_height(ds); vnc_lock_output(vs); vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); @@ -573,18 +573,20 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) return ptr; } -static void vnc_dpy_resize(DisplayState *ds) +static void vnc_dpy_switch(DisplayChangeListener *dcl, + DisplaySurface *surface) { - VncDisplay *vd = ds->opaque; + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncState *vs; vnc_abort_display_jobs(vd); /* server surface */ qemu_pixman_image_unref(vd->server); + vd->ds = surface; vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT, - ds_get_width(ds), - ds_get_height(ds), + surface_width(vd->ds), + surface_height(vd->ds), NULL, 0); /* guest surface */ @@ -593,8 +595,8 @@ static void vnc_dpy_resize(DisplayState *ds) console_color_init(ds); #endif qemu_pixman_image_unref(vd->guest.fb); - vd->guest.fb = pixman_image_ref(ds->surface->image); - vd->guest.format = ds->surface->format; + vd->guest.fb = pixman_image_ref(surface->image); + vd->guest.format = surface->format; memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty)); QTAILQ_FOREACH(vs, &vd->clients, next) { @@ -735,9 +737,11 @@ static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, i vnc_flush(vs); } -static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) +static void vnc_dpy_copy(DisplayChangeListener *dcl, + int src_x, int src_y, + int dst_x, int dst_y, int w, int h) { - VncDisplay *vd = ds->opaque; + VncDisplay *vd = container_of(dcl, VncDisplay, dcl); VncState *vs, *vn; uint8_t *src_row; uint8_t *dst_row; @@ -806,7 +810,8 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int } } -static void vnc_mouse_set(DisplayState *ds, int x, int y, int visible) +static void vnc_mouse_set(DisplayChangeListener *dcl, + int x, int y, int visible) { /* can we ask the client(s) to move the pointer ??? */ } @@ -832,7 +837,8 @@ static int vnc_cursor_define(VncState *vs) return -1; } -static void vnc_dpy_cursor_define(DisplayState *ds, QEMUCursor *c) +static void vnc_dpy_cursor_define(DisplayChangeListener *dcl, + QEMUCursor *c) { VncDisplay *vd = vnc_display; VncState *vs; @@ -1059,7 +1065,7 @@ void vnc_disconnect_finish(VncState *vs) } if (QTAILQ_EMPTY(&vs->vd->clients)) { - dcl->idle = 1; + vs->vd->dcl.idle = 1; } vnc_remove_timer(vs->vd); @@ -1453,7 +1459,8 @@ static void check_pointer_type_change(Notifier *notifier, void *data) vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); vnc_framebuffer_update(vs, absolute, 0, - ds_get_width(vs->ds), ds_get_height(vs->ds), + surface_width(vs->vd->ds), + surface_height(vs->vd->ds), VNC_ENCODING_POINTER_TYPE_CHANGE); vnc_unlock_output(vs); vnc_flush(vs); @@ -1465,6 +1472,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) { int buttons = 0; int dz = 0; + int width = surface_width(vs->vd->ds); + int height = surface_height(vs->vd->ds); if (button_mask & 0x01) buttons |= MOUSE_EVENT_LBUTTON; @@ -1478,10 +1487,8 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) dz = 1; if (vs->absolute) { - kbd_mouse_event(ds_get_width(vs->ds) > 1 ? - x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000, - ds_get_height(vs->ds) > 1 ? - y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000, + kbd_mouse_event(width > 1 ? x * 0x7FFF / (width - 1) : 0x4000, + height > 1 ? y * 0x7FFF / (height - 1) : 0x4000, dz, buttons); } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) { x -= 0x7FFF; @@ -1771,12 +1778,15 @@ static void framebuffer_update_request(VncState *vs, int incremental, int w, int h) { int i; - const size_t width = ds_get_width(vs->ds) / 16; + const size_t width = surface_width(vs->vd->ds) / 16; + const size_t height = surface_height(vs->vd->ds); - if (y_position > ds_get_height(vs->ds)) - y_position = ds_get_height(vs->ds); - if (y_position + h >= ds_get_height(vs->ds)) - h = ds_get_height(vs->ds) - y_position; + if (y_position > height) { + y_position = height; + } + if (y_position + h >= height) { + h = height - y_position; + } vs->need_update = 1; if (!incremental) { @@ -1795,7 +1805,9 @@ static void send_ext_key_event_ack(VncState *vs) vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); - vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), + vnc_framebuffer_update(vs, 0, 0, + surface_width(vs->vd->ds), + surface_height(vs->vd->ds), VNC_ENCODING_EXT_KEY_EVENT); vnc_unlock_output(vs); vnc_flush(vs); @@ -1807,7 +1819,9 @@ static void send_ext_audio_ack(VncState *vs) vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); - vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), + vnc_framebuffer_update(vs, 0, 0, + surface_width(vs->vd->ds), + surface_height(vs->vd->ds), VNC_ENCODING_AUDIO); vnc_unlock_output(vs); vnc_flush(vs); @@ -1972,16 +1986,6 @@ static void pixel_format_message (VncState *vs) { vs->write_pixels = vnc_write_pixels_copy; } -static void vnc_dpy_setdata(DisplayState *ds) -{ - VncDisplay *vd = ds->opaque; - - qemu_pixman_image_unref(vd->guest.fb); - vd->guest.fb = pixman_image_ref(ds->surface->image); - vd->guest.format = ds->surface->format; - vnc_dpy_update(ds, 0, 0, ds_get_width(ds), ds_get_height(ds)); -} - static void vnc_colordepth(VncState *vs) { if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { @@ -1990,8 +1994,10 @@ static void vnc_colordepth(VncState *vs) vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); vnc_write_u8(vs, 0); vnc_write_u16(vs, 1); /* number of rects */ - vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), - ds_get_height(vs->ds), VNC_ENCODING_WMVi); + vnc_framebuffer_update(vs, 0, 0, + surface_width(vs->vd->ds), + surface_height(vs->vd->ds), + VNC_ENCODING_WMVi); pixel_format_message(vs); vnc_unlock_output(vs); vnc_flush(vs); @@ -2207,8 +2213,8 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) } vnc_set_share_mode(vs, mode); - vs->client_width = ds_get_width(vs->ds); - vs->client_height = ds_get_height(vs->ds); + vs->client_width = surface_width(vs->vd->ds); + vs->client_height = surface_height(vs->vd->ds); vnc_write_u16(vs, vs->client_width); vnc_write_u16(vs, vs->client_height); @@ -2686,7 +2692,7 @@ static void vnc_init_timer(VncDisplay *vd) vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) { vd->timer = qemu_new_timer_ms(rt_clock, vnc_refresh, vd); - vnc_dpy_resize(vd->ds); + vga_hw_update(); vnc_refresh(vd); } } @@ -2725,7 +2731,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth, bool websocket) } VNC_DEBUG("New client on socket %d\n", csock); - dcl->idle = 0; + vd->dcl.idle = 0; socket_set_nonblock(vs->csock); #ifdef CONFIG_VNC_WS if (websocket) { @@ -2756,7 +2762,6 @@ void vnc_init_state(VncState *vs) vs->initialized = true; VncDisplay *vd = vs->vd; - vs->ds = vd->ds; vs->last_x = -1; vs->last_y = -1; @@ -2822,14 +2827,20 @@ static void vnc_listen_websocket_read(void *opaque) } #endif /* CONFIG_VNC_WS */ +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "vnc", + .dpy_gfx_copy = vnc_dpy_copy, + .dpy_gfx_update = vnc_dpy_update, + .dpy_gfx_switch = vnc_dpy_switch, + .dpy_mouse_set = vnc_mouse_set, + .dpy_cursor_define = vnc_dpy_cursor_define, +}; + void vnc_display_init(DisplayState *ds) { VncDisplay *vs = g_malloc0(sizeof(*vs)); - dcl = g_malloc0(sizeof(DisplayChangeListener)); - - ds->opaque = vs; - dcl->idle = 1; + vs->dcl.idle = 1; vnc_display = vs; vs->lsock = -1; @@ -2837,7 +2848,6 @@ void vnc_display_init(DisplayState *ds) vs->lwebsock = -1; #endif - vs->ds = ds; QTAILQ_INIT(&vs->clients); vs->expires = TIME_MAX; @@ -2852,19 +2862,14 @@ void vnc_display_init(DisplayState *ds) qemu_mutex_init(&vs->mutex); vnc_start_worker_thread(); - dcl->dpy_gfx_copy = vnc_dpy_copy; - dcl->dpy_gfx_update = vnc_dpy_update; - dcl->dpy_gfx_resize = vnc_dpy_resize; - dcl->dpy_gfx_setdata = vnc_dpy_setdata; - dcl->dpy_mouse_set = vnc_mouse_set; - dcl->dpy_cursor_define = vnc_dpy_cursor_define; - register_displaychangelistener(ds, dcl); + vs->dcl.ops = &dcl_ops; + register_displaychangelistener(ds, &vs->dcl); } static void vnc_display_close(DisplayState *ds) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; if (!vs) return; @@ -2895,7 +2900,7 @@ static void vnc_display_close(DisplayState *ds) static int vnc_display_disable_login(DisplayState *ds) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; if (!vs) { return -1; @@ -2915,7 +2920,7 @@ static int vnc_display_disable_login(DisplayState *ds) int vnc_display_password(DisplayState *ds, const char *password) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; if (!vs) { return -EINVAL; @@ -2941,7 +2946,7 @@ int vnc_display_password(DisplayState *ds, const char *password) int vnc_display_pw_expire(DisplayState *ds, time_t expires) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; if (!vs) { return -EINVAL; @@ -2953,14 +2958,14 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires) char *vnc_display_local_addr(DisplayState *ds) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; return vnc_socket_local_addr("%s:%s", vs->lsock); } void vnc_display_open(DisplayState *ds, const char *display, Error **errp) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; const char *options; int password = 0; int reverse = 0; @@ -3266,7 +3271,7 @@ fail: void vnc_display_add_client(DisplayState *ds, int csock, int skipauth) { - VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; + VncDisplay *vs = vnc_display; vnc_connect(vs, csock, skipauth, 0); } @@ -150,7 +150,8 @@ struct VncDisplay bool websocket; char *ws_display; #endif - DisplayState *ds; + DisplaySurface *ds; + DisplayChangeListener dcl; kbd_layout_t *kbd_layout; int lock_key_sync; QemuMutex mutex; @@ -247,7 +248,6 @@ struct VncState { int csock; - DisplayState *ds; DECLARE_BITMAP(dirty[VNC_MAX_HEIGHT], VNC_DIRTY_BITS); uint8_t **lossy_rect; /* Not an Array to avoid costly memcpy in * vnc-jobs-async.c */ diff --git a/util/Makefile.objs b/util/Makefile.objs index cad5ce87db..557bda7a15 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -9,3 +9,4 @@ util-obj-y += error.o qemu-error.o util-obj-$(CONFIG_POSIX) += compatfd.o util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o util-obj-y += qemu-option.o qemu-progress.o +util-obj-y += hexdump.o diff --git a/util/hexdump.c b/util/hexdump.c new file mode 100644 index 0000000000..0d0efc86de --- /dev/null +++ b/util/hexdump.c @@ -0,0 +1,37 @@ +/* + * Helper to hexdump a buffer + * + * Copyright (c) 2013 Red Hat, Inc. + * Copyright (c) 2013 Gerd Hoffmann <kraxel@redhat.com> + * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com> + * Copyright (c) 2013 Xilinx, Inc + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu-common.h" + +void hexdump(const char *buf, FILE *fp, const char *prefix, size_t size) +{ + unsigned int b; + + for (b = 0; b < size; b++) { + if ((b % 16) == 0) { + fprintf(fp, "%s: %04x:", prefix, b); + } + if ((b % 4) == 0) { + fprintf(fp, " "); + } + fprintf(fp, " %02x", (unsigned char)buf[b]); + if ((b % 16) == 15) { + fprintf(fp, "\n"); + } + } + if ((b % 16) != 0) { + fprintf(fp, "\n"); + } +} diff --git a/util/iov.c b/util/iov.c index fbe675d373..9dae318197 100644 --- a/util/iov.c +++ b/util/iov.c @@ -201,32 +201,18 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt, FILE *fp, const char *prefix, size_t limit) { - unsigned int i, v, b; - uint8_t *c; - - c = iov[0].iov_base; - for (i = 0, v = 0, b = 0; b < limit; i++, b++) { - if (i == iov[v].iov_len) { - i = 0; v++; - if (v == iov_cnt) { - break; - } - c = iov[v].iov_base; - } - if ((b % 16) == 0) { - fprintf(fp, "%s: %04x:", prefix, b); - } - if ((b % 4) == 0) { - fprintf(fp, " "); - } - fprintf(fp, " %02x", c[i]); - if ((b % 16) == 15) { - fprintf(fp, "\n"); - } - } - if ((b % 16) != 0) { - fprintf(fp, "\n"); + int v; + size_t size = 0; + char *buf; + + for (v = 0; v < iov_cnt; v++) { + size += iov[v].iov_len; } + size = size > limit ? limit : size; + buf = g_malloc(size); + iov_to_buf(iov, iov_cnt, 0, buf, size); + hexdump(buf, fp, prefix, size); + g_free(buf); } unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt, @@ -1639,13 +1639,13 @@ void gui_setup_refresh(DisplayState *ds) bool have_text = false; QLIST_FOREACH(dcl, &ds->listeners, next) { - if (dcl->dpy_refresh != NULL) { + if (dcl->ops->dpy_refresh != NULL) { need_timer = true; } - if (dcl->dpy_gfx_update != NULL) { + if (dcl->ops->dpy_gfx_update != NULL) { have_gfx = true; } - if (dcl->dpy_text_update != NULL) { + if (dcl->ops->dpy_text_update != NULL) { have_text = true; } } |