From e3a99a8a62027a83d3296ea4234973522e86cfeb Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 26 Jul 2020 11:24:30 +0200 Subject: hw/hppa: Sync hppa_hardware.h file with SeaBIOS sources The hppa_hardware.h file is shared with SeaBIOS. Sync it. Acked-by: Richard Henderson Signed-off-by: Helge Deller --- hw/hppa/hppa_hardware.h | 6 ++++++ hw/hppa/lasi.c | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index 4a2fe2df60..cdb7fa6240 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -17,6 +17,7 @@ #define LASI_UART_HPA 0xffd05000 #define LASI_SCSI_HPA 0xffd06000 #define LASI_LAN_HPA 0xffd07000 +#define LASI_RTC_HPA 0xffd09000 #define LASI_LPT_HPA 0xffd02000 #define LASI_AUDIO_HPA 0xffd04000 #define LASI_PS2KBD_HPA 0xffd08000 @@ -37,10 +38,15 @@ #define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR) #define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA) +/* QEMU fw_cfg interface port */ +#define QEMU_FW_CFG_IO_BASE (MEMORY_HPA + 0x80) + #define PORT_SERIAL1 (DINO_UART_HPA + 0x800) #define PORT_SERIAL2 (LASI_UART_HPA + 0x800) #define HPPA_MAX_CPUS 8 /* max. number of SMP CPUs */ #define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */ +#define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */ + #endif diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 19974034f3..ffcbb988b8 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -54,8 +54,6 @@ #define LASI_CHIP(obj) \ OBJECT_CHECK(LasiState, (obj), TYPE_LASI_CHIP) -#define LASI_RTC_HPA (LASI_HPA + 0x9000) - typedef struct LasiState { PCIHostState parent_obj; -- cgit v1.2.3 From 28b71a2e42553a3eb8367fec2a2f70265ec77829 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 27 Jul 2020 22:43:44 +0200 Subject: hw/hppa: Implement proper SeaBIOS version check It's important that the SeaBIOS hppa firmware is at least at a minimal level to ensure proper interaction between qemu and firmware. Implement a proper firmware version check by telling SeaBIOS via the fw_cfg interface which minimal SeaBIOS version is required by this running qemu instance. If the firmware detects that it's too old, it will stop. Signed-off-by: Helge Deller --- hw/hppa/machine.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'hw') diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 49155537cd..90aeefe2a4 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -25,6 +25,8 @@ #define MAX_IDE_BUS 2 +#define MIN_SEABIOS_HPPA_VERSION 1 /* require at least this fw version */ + static ISABus *hppa_isa_bus(void) { ISABus *isa_bus; @@ -56,6 +58,23 @@ static uint64_t cpu_hppa_to_phys(void *opaque, uint64_t addr) static HPPACPU *cpu[HPPA_MAX_CPUS]; static uint64_t firmware_entry; +static FWCfgState *create_fw_cfg(MachineState *ms) +{ + FWCfgState *fw_cfg; + uint64_t val; + + fw_cfg = fw_cfg_init_mem(QEMU_FW_CFG_IO_BASE, QEMU_FW_CFG_IO_BASE + 4); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, HPPA_MAX_CPUS); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ram_size); + + val = cpu_to_le64(MIN_SEABIOS_HPPA_VERSION); + fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version", + g_memdup(&val, sizeof(val)), sizeof(val)); + + return fw_cfg; +} + static void machine_hppa_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; @@ -118,6 +137,9 @@ static void machine_hppa_init(MachineState *machine) 115200, serial_hd(0), DEVICE_BIG_ENDIAN); } + /* fw_cfg configuration interface */ + create_fw_cfg(machine); + /* SCSI disk setup. */ dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a")); lsi53c8xx_handle_legacy_cmdline(dev); -- cgit v1.2.3 From a24d2cf30c06e85dd06c68ad2f162ca53f3b9bc8 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sat, 29 Feb 2020 10:50:40 +0100 Subject: hw/display/artist.c: fix out of bounds check Fix the following runtime warning with artist framebuffer: "write outside bounds: wants 1256x1023, max size 1280x1024" Reviewed-by: Richard Henderson Signed-off-by: Sven Schnelle Signed-off-by: Helge Deller --- hw/display/artist.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index 6261bfe65b..de56200dbf 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -340,14 +340,13 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, { struct vram_buffer *buf; uint32_t vram_bitmask = s->vram_bitmask; - int mask, i, pix_count, pix_length, offset, height, width; + int mask, i, pix_count, pix_length, offset, width; uint8_t *data8, *p; pix_count = vram_write_pix_per_transfer(s); pix_length = vram_pixel_length(s); buf = vram_write_buffer(s); - height = buf->height; width = buf->width; if (s->cmap_bm_access) { @@ -367,13 +366,6 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, pix_count = size * 8; } - if (posy * width + posx + pix_count > buf->size) { - qemu_log("write outside bounds: wants %dx%d, max size %dx%d\n", - posx, posy, width, height); - return; - } - - switch (pix_length) { case 0: if (s->image_bitmap_op & 0x20000000) { @@ -381,8 +373,11 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, } for (i = 0; i < pix_count; i++) { - artist_rop8(s, p + offset + pix_count - 1 - i, - (data & 1) ? (s->plane_mask >> 24) : 0); + uint32_t off = offset + pix_count - 1 - i; + if (off < buf->size) { + artist_rop8(s, p + off, + (data & 1) ? (s->plane_mask >> 24) : 0); + } data >>= 1; } memory_region_set_dirty(&buf->mr, offset, pix_count); @@ -398,7 +393,10 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, for (i = 3; i >= 0; i--) { if (!(s->image_bitmap_op & 0x20000000) || s->vram_bitmask & (1 << (28 + i))) { - artist_rop8(s, p + offset + 3 - i, data8[ROP8OFF(i)]); + uint32_t off = offset + 3 - i; + if (off < buf->size) { + artist_rop8(s, p + off, data8[ROP8OFF(i)]); + } } } memory_region_set_dirty(&buf->mr, offset, 3); @@ -420,7 +418,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, break; } - for (i = 0; i < pix_count; i++) { + for (i = 0; i < pix_count && offset + i < buf->size; i++) { mask = 1 << (pix_count - 1 - i); if (!(s->image_bitmap_op & 0x20000000) || -- cgit v1.2.3 From b899fe41ceb9c684fa135a081f4c9749400a61d3 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Mon, 3 Aug 2020 07:41:46 +0200 Subject: hw/hppa/lasi: Don't abort on invalid IMR value NetBSD initializes the LASI IMR value with 0xffffffff to disable all LASI interrupts. This triggered an assert() and stopped the emulation. By replacing the check with a warning in the guest log we now allow NetBSD to boot again. Signed-off-by: Helge Deller --- hw/hppa/lasi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index ffcbb988b8..194aa3e619 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "qemu/log.h" #include "qapi/error.h" #include "cpu.h" #include "trace.h" @@ -170,8 +171,11 @@ static MemTxResult lasi_chip_write_with_attrs(void *opaque, hwaddr addr, /* read-only. */ break; case LASI_IMR: - s->imr = val; /* 0x20 ?? */ - assert((val & LASI_IRQ_BITS) == val); + s->imr = val; + if (((val & LASI_IRQ_BITS) != val) && (val != 0xffffffff)) + qemu_log_mask(LOG_GUEST_ERROR, + "LASI: tried to set invalid %lx IMR value.\n", + (unsigned long) val); break; case LASI_IPR: /* Any write to IPR clears the register. */ -- cgit v1.2.3 From b87a7355de04a2771c11824ea791802c052c979c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 23 May 2020 21:15:15 +0200 Subject: hw/display/artist: Check offset in draw_line to avoid buffer over-run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invalid I/O writes can craft an offset out of the vram_buffer range. We avoid: Program terminated with signal SIGSEGV, Segmentation fault. 284 *dst &= ~plane_mask; (gdb) bt #0 0x000055d5dccdc5c0 in artist_rop8 (s=0x55d5defee510, dst=0x7f8e84ed8216 , val=0 '\000') at hw/display/artist.c:284 #1 0x000055d5dccdcf83 in fill_window (s=0x55d5defee510, startx=22, starty=5674, width=65, height=5697) at hw/display/artist.c:551 #2 0x000055d5dccddfb9 in artist_reg_write (opaque=0x55d5defee510, addr=1051140, val=4265537, size=4) at hw/display/artist.c:902 #3 0x000055d5dcb42a7c in memory_region_write_accessor (mr=0x55d5defeea10, addr=1051140, value=0x7ffe57db08c8, size=4, shift=0, mask=4294967295, attrs=...) at memory.c:483 Reported-by: LLVM libFuzzer Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Helge Deller --- hw/display/artist.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index de56200dbf..a206afe641 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -555,7 +555,7 @@ static void fill_window(ARTISTState *s, int startx, int starty, static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, bool update_start, int skip_pix, int max_pix) { - struct vram_buffer *buf; + struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP]; uint8_t color; int dx, dy, t, e, x, y, incy, diago, horiz; bool c1; @@ -563,6 +563,12 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, trace_artist_draw_line(x1, y1, x2, y2); + if (x1 * y1 >= buf->size || x2 * y2 >= buf->size) { + qemu_log_mask(LOG_GUEST_ERROR, + "draw_line (%d,%d) (%d,%d)\n", x1, y1, x2, y2); + return; + } + if (update_start) { s->vram_start = (x2 << 16) | y2; } @@ -620,7 +626,6 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, x = x1; y = y1; color = artist_get_color(s); - buf = &s->vram_buffer[ARTIST_BUFFER_AP]; do { if (c1) { -- cgit v1.2.3 From 84a7b7741a62ede8ff01ae151e59b2a16bda629b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 23 May 2020 21:15:16 +0200 Subject: hw/display/artist: Refactor artist_rop8() to avoid buffer over-run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Invalid I/O writes can craft an offset out of the vram_buffer range. Instead of passing an unsafe pointer to artist_rop8(), pass the vram_buffer and the offset. We can now check if the offset is in range before accessing it. We avoid: Program terminated with signal SIGSEGV, Segmentation fault. 284 *dst &= ~plane_mask; (gdb) bt #0 0x000056367b2085c0 in artist_rop8 (s=0x56367d38b510, dst=0x7f9f972fffff , val=0 '\000') at hw/display/artist.c:284 #1 0x000056367b209325 in draw_line (s=0x56367d38b510, x1=-20480, y1=-1, x2=0, y2=17920, update_start=true, skip_pix=-1, max_pix=-1) at hw/display/artist.c:646 Reported-by: LLVM libFuzzer Buglink: https://bugs.launchpad.net/qemu/+bug/1880326 Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Helge Deller --- hw/display/artist.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index a206afe641..47de17b9e9 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -273,11 +273,20 @@ static artist_rop_t artist_get_op(ARTISTState *s) return (s->image_bitmap_op >> 8) & 0xf; } -static void artist_rop8(ARTISTState *s, uint8_t *dst, uint8_t val) +static void artist_rop8(ARTISTState *s, struct vram_buffer *buf, + int offset, uint8_t val) { - const artist_rop_t op = artist_get_op(s); - uint8_t plane_mask = s->plane_mask & 0xff; + uint8_t plane_mask; + uint8_t *dst; + + if (offset < 0 || offset >= buf->size) { + qemu_log_mask(LOG_GUEST_ERROR, + "rop8 offset:%d bufsize:%u\n", offset, buf->size); + return; + } + dst = buf->data + offset; + plane_mask = s->plane_mask & 0xff; switch (op) { case ARTIST_ROP_CLEAR: @@ -375,7 +384,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, for (i = 0; i < pix_count; i++) { uint32_t off = offset + pix_count - 1 - i; if (off < buf->size) { - artist_rop8(s, p + off, + artist_rop8(s, buf, off, (data & 1) ? (s->plane_mask >> 24) : 0); } data >>= 1; @@ -395,7 +404,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, s->vram_bitmask & (1 << (28 + i))) { uint32_t off = offset + 3 - i; if (off < buf->size) { - artist_rop8(s, p + off, data8[ROP8OFF(i)]); + artist_rop8(s, buf, off, data8[ROP8OFF(i)]); } } } @@ -424,10 +433,10 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, if (!(s->image_bitmap_op & 0x20000000) || (vram_bitmask & mask)) { if (data & mask) { - artist_rop8(s, p + offset + i, s->fg_color); + artist_rop8(s, buf, offset + i, s->fg_color); } else { if (!(s->image_bitmap_op & 0x10000002)) { - artist_rop8(s, p + offset + i, s->bg_color); + artist_rop8(s, buf, offset + i, s->bg_color); } } } @@ -505,7 +514,7 @@ static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x, if (dst + column > buf->size || src + column > buf->size) { continue; } - artist_rop8(s, buf->data + dst + column, buf->data[src + column]); + artist_rop8(s, buf, dst + column, buf->data[src + column]); } } @@ -546,7 +555,7 @@ static void fill_window(ARTISTState *s, int startx, int starty, offset = y * s->width; for (x = startx; x < startx + width; x++) { - artist_rop8(s, buf->data + offset + x, color); + artist_rop8(s, buf, offset + x, color); } } artist_invalidate_lines(buf, starty, height); @@ -559,7 +568,6 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, uint8_t color; int dx, dy, t, e, x, y, incy, diago, horiz; bool c1; - uint8_t *p; trace_artist_draw_line(x1, y1, x2, y2); @@ -628,16 +636,18 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, color = artist_get_color(s); do { + int ofs; + if (c1) { - p = buf->data + x * s->width + y; + ofs = x * s->width + y; } else { - p = buf->data + y * s->width + x; + ofs = y * s->width + x; } if (skip_pix > 0) { skip_pix--; } else { - artist_rop8(s, p, color); + artist_rop8(s, buf, ofs, color); } if (e > 0) { @@ -771,10 +781,10 @@ static void font_write16(ARTISTState *s, uint16_t val) for (i = 0; i < 16; i++) { mask = 1 << (15 - i); if (val & mask) { - artist_rop8(s, buf->data + offset + i, color); + artist_rop8(s, buf, offset + i, color); } else { if (!(s->image_bitmap_op & 0x20000000)) { - artist_rop8(s, buf->data + offset + i, s->bg_color); + artist_rop8(s, buf, offset + i, s->bg_color); } } } -- cgit v1.2.3 From 8bd0d5b5ef0552d66968a8fdefc5a9080eb358e3 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 8 Aug 2020 22:22:37 +0200 Subject: Revert "hw/display/artist: Avoid drawing line when nothing to display" This reverts commit b0f6455feac97e41045ee394e11c24d92c370f6e. It's wrong. A line could even be a dot. Signed-off-by: Helge Deller --- hw/display/artist.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index 47de17b9e9..f37aa9eb49 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -591,9 +591,6 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, } else { dy = y1 - y2; } - if (!dx || !dy) { - return; - } c1 = false; if (dy > dx) { -- cgit v1.2.3 From a501bfc91763d4642390090dd4e6039d67b63702 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 9 Aug 2020 15:35:38 +0200 Subject: hw/display/artist: Prevent out of VRAM buffer accesses Simplify various bounds checks by changing parameters like row and column numbers to become unsigned instead of signed. With that we can check if the calculated offset is bigger than the size of the VRAM region and bail out if not. Reported-by: LLVM libFuzzer Reported-by: Alexander Bulekov Buglink: https://bugs.launchpad.net/qemu/+bug/1880326 Buglink: https://bugs.launchpad.net/qemu/+bug/1890310 Buglink: https://bugs.launchpad.net/qemu/+bug/1890311 Buglink: https://bugs.launchpad.net/qemu/+bug/1890312 Buglink: https://bugs.launchpad.net/qemu/+bug/1890370 Acked-by: Alexander Bulekov Signed-off-by: Helge Deller --- hw/display/artist.c | 110 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 41 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index f37aa9eb49..46eaa10dae 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -35,9 +35,9 @@ struct vram_buffer { MemoryRegion mr; uint8_t *data; - int size; - int width; - int height; + unsigned int size; + unsigned int width; + unsigned int height; }; typedef struct ARTISTState { @@ -274,15 +274,15 @@ static artist_rop_t artist_get_op(ARTISTState *s) } static void artist_rop8(ARTISTState *s, struct vram_buffer *buf, - int offset, uint8_t val) + unsigned int offset, uint8_t val) { const artist_rop_t op = artist_get_op(s); uint8_t plane_mask; uint8_t *dst; - if (offset < 0 || offset >= buf->size) { + if (offset >= buf->size) { qemu_log_mask(LOG_GUEST_ERROR, - "rop8 offset:%d bufsize:%u\n", offset, buf->size); + "rop8 offset:%u bufsize:%u\n", offset, buf->size); return; } dst = buf->data + offset; @@ -294,8 +294,7 @@ static void artist_rop8(ARTISTState *s, struct vram_buffer *buf, break; case ARTIST_ROP_COPY: - *dst &= ~plane_mask; - *dst |= val & plane_mask; + *dst = (*dst & ~plane_mask) | (val & plane_mask); break; case ARTIST_ROP_XOR: @@ -349,7 +348,8 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, { struct vram_buffer *buf; uint32_t vram_bitmask = s->vram_bitmask; - int mask, i, pix_count, pix_length, offset, width; + int mask, i, pix_count, pix_length; + unsigned int offset, width; uint8_t *data8, *p; pix_count = vram_write_pix_per_transfer(s); @@ -364,8 +364,7 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, offset = posy * width + posx; } - if (!buf->size) { - qemu_log("write to non-existent buffer\n"); + if (!buf->size || offset >= buf->size) { return; } @@ -394,7 +393,9 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, case 3: if (s->cmap_bm_access) { - *(uint32_t *)(p + offset) = data; + if (offset + 3 < buf->size) { + *(uint32_t *)(p + offset) = data; + } break; } data8 = (uint8_t *)&data; @@ -464,12 +465,14 @@ static void vram_bit_write(ARTISTState *s, int posx, int posy, bool incr_x, } } -static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x, - int dest_y, int width, int height) +static void block_move(ARTISTState *s, + unsigned int source_x, unsigned int source_y, + unsigned int dest_x, unsigned int dest_y, + unsigned int width, unsigned int height) { struct vram_buffer *buf; int line, endline, lineincr, startcolumn, endcolumn, columnincr, column; - uint32_t dst, src; + unsigned int dst, src; trace_artist_block_move(source_x, source_y, dest_x, dest_y, width, height); @@ -481,6 +484,12 @@ static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x, } buf = &s->vram_buffer[ARTIST_BUFFER_AP]; + if (height > buf->height) { + height = buf->height; + } + if (width > buf->width) { + width = buf->width; + } if (dest_y > source_y) { /* move down */ @@ -507,24 +516,27 @@ static void block_move(ARTISTState *s, int source_x, int source_y, int dest_x, } for ( ; line != endline; line += lineincr) { - src = source_x + ((line + source_y) * buf->width); - dst = dest_x + ((line + dest_y) * buf->width); + src = source_x + ((line + source_y) * buf->width) + startcolumn; + dst = dest_x + ((line + dest_y) * buf->width) + startcolumn; for (column = startcolumn; column != endcolumn; column += columnincr) { - if (dst + column > buf->size || src + column > buf->size) { + if (dst >= buf->size || src >= buf->size) { continue; } - artist_rop8(s, buf, dst + column, buf->data[src + column]); + artist_rop8(s, buf, dst, buf->data[src]); + src += columnincr; + dst += columnincr; } } artist_invalidate_lines(buf, dest_y, height); } -static void fill_window(ARTISTState *s, int startx, int starty, - int width, int height) +static void fill_window(ARTISTState *s, + unsigned int startx, unsigned int starty, + unsigned int width, unsigned int height) { - uint32_t offset; + unsigned int offset; uint8_t color = artist_get_color(s); struct vram_buffer *buf; int x, y; @@ -561,7 +573,9 @@ static void fill_window(ARTISTState *s, int startx, int starty, artist_invalidate_lines(buf, starty, height); } -static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, +static void draw_line(ARTISTState *s, + unsigned int x1, unsigned int y1, + unsigned int x2, unsigned int y2, bool update_start, int skip_pix, int max_pix) { struct vram_buffer *buf = &s->vram_buffer[ARTIST_BUFFER_AP]; @@ -571,12 +585,12 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, trace_artist_draw_line(x1, y1, x2, y2); - if (x1 * y1 >= buf->size || x2 * y2 >= buf->size) { - qemu_log_mask(LOG_GUEST_ERROR, - "draw_line (%d,%d) (%d,%d)\n", x1, y1, x2, y2); - return; + if ((x1 >= buf->width && x2 >= buf->width) || + (y1 >= buf->height && y2 >= buf->height)) { + return; } + if (update_start) { s->vram_start = (x2 << 16) | y2; } @@ -633,7 +647,7 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2, color = artist_get_color(s); do { - int ofs; + unsigned int ofs; if (c1) { ofs = x * s->width + y; @@ -765,13 +779,14 @@ static void font_write16(ARTISTState *s, uint16_t val) uint16_t mask; int i; - int startx = artist_get_x(s->vram_start); - int starty = artist_get_y(s->vram_start) + s->font_write_pos_y; - int offset = starty * s->width + startx; + unsigned int startx = artist_get_x(s->vram_start); + unsigned int starty = artist_get_y(s->vram_start) + s->font_write_pos_y; + unsigned int offset = starty * s->width + startx; buf = &s->vram_buffer[ARTIST_BUFFER_AP]; - if (offset + 16 > buf->size) { + if (startx >= buf->width || starty >= buf->height || + offset + 16 >= buf->size) { return; } @@ -1135,7 +1150,7 @@ static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, struct vram_buffer *buf; int posy = (addr >> 11) & 0x3ff; int posx = addr & 0x7ff; - uint32_t offset; + unsigned int offset; trace_artist_vram_write(size, addr, val); if (s->cmap_bm_access) { @@ -1156,18 +1171,28 @@ static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, } offset = posy * buf->width + posx; + if (offset >= buf->size) { + return; + } + switch (size) { case 4: - *(uint32_t *)(buf->data + offset) = be32_to_cpu(val); - memory_region_set_dirty(&buf->mr, offset, 4); + if (offset + 3 < buf->size) { + *(uint32_t *)(buf->data + offset) = be32_to_cpu(val); + memory_region_set_dirty(&buf->mr, offset, 4); + } break; case 2: - *(uint16_t *)(buf->data + offset) = be16_to_cpu(val); - memory_region_set_dirty(&buf->mr, offset, 2); + if (offset + 1 < buf->size) { + *(uint16_t *)(buf->data + offset) = be16_to_cpu(val); + memory_region_set_dirty(&buf->mr, offset, 2); + } break; case 1: - *(uint8_t *)(buf->data + offset) = val; - memory_region_set_dirty(&buf->mr, offset, 1); + if (offset < buf->size) { + *(uint8_t *)(buf->data + offset) = val; + memory_region_set_dirty(&buf->mr, offset, 1); + } break; default: break; @@ -1183,9 +1208,12 @@ static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size) if (s->cmap_bm_access) { buf = &s->vram_buffer[ARTIST_BUFFER_CMAP]; - val = *(uint32_t *)(buf->data + addr); + val = 0; + if (addr < buf->size && addr + 3 < buf->size) { + val = *(uint32_t *)(buf->data + addr); + } trace_artist_vram_read(size, addr, 0, 0, val); - return 0; + return val; } buf = vram_read_buffer(s); -- cgit v1.2.3 From e0cf02ce680f11893aca9642e76d6ae68b9375af Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 8 Aug 2020 22:29:01 +0200 Subject: hw/display/artist: Unbreak size mismatch memory accesses Commit 5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid") broke the artist driver in a way that the dtwm window manager on HP-UX rendered wrong. Fixes: 5d971f9e6725 ("memory: Revert "memory: accept mismatching sizes in memory_region_access_valid") Signed-off-by: Sven Schnelle Signed-off-by: Helge Deller --- hw/display/artist.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index 46eaa10dae..44bb67bbc3 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1237,20 +1237,16 @@ static const MemoryRegionOps artist_reg_ops = { .read = artist_reg_read, .write = artist_reg_write, .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, + .impl.min_access_size = 1, + .impl.max_access_size = 4, }; static const MemoryRegionOps artist_vram_ops = { .read = artist_vram_read, .write = artist_vram_write, .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, + .impl.min_access_size = 1, + .impl.max_access_size = 4, }; static void artist_draw_cursor(ARTISTState *s) -- cgit v1.2.3 From f9e9f7149027906785949d49b4e4c9b9ec896203 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sat, 8 Aug 2020 21:56:29 +0200 Subject: hw/display/artist: Fix invalidation of lines in artist_draw_line() The old code didn't invalidate correctly when vertical lines were drawn. Fix this and move the invalidation out of the loop. Signed-off-by: Sven Schnelle Signed-off-by: Helge Deller --- hw/display/artist.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index 44bb67bbc3..a959b2c158 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -662,7 +662,6 @@ static void draw_line(ARTISTState *s, } if (e > 0) { - artist_invalidate_lines(buf, y, 1); y += incy; e += diago; } else { @@ -670,6 +669,10 @@ static void draw_line(ARTISTState *s, } x++; } while (x <= x2 && (max_pix == -1 || --max_pix > 0)); + if (c1) + artist_invalidate_lines(buf, x, dy+1); + else + artist_invalidate_lines(buf, y, dx+1); } static void draw_line_pattern_start(ARTISTState *s) -- cgit v1.2.3 From 2f8cd515477edab1cbf38ecbdbfa2cac13ce1550 Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sat, 8 Aug 2020 20:51:57 +0200 Subject: hw/display/artist: Fix invalidation of lines near screen border If parts of the invalidated screen lines are outside of the VRAM buffer, the code skips the whole invalidate. This is incorrect when only parts of the buffer are invisble - which is the case when the mouse cursor is located near the screen border. Signed-off-by: Sven Schnelle Signed-off-by: Helge Deller --- hw/display/artist.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/display/artist.c b/hw/display/artist.c index a959b2c158..71982559c6 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -206,7 +206,12 @@ static void artist_invalidate_lines(struct vram_buffer *buf, int starty, int height) { int start = starty * buf->width; - int size = height * buf->width; + int size; + + if (starty + height > buf->height) + height = buf->height - starty; + + size = height * buf->width; if (start + size <= buf->size) { memory_region_set_dirty(&buf->mr, start, size); -- cgit v1.2.3