artist out of bounds fixes

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCX0bPowAKCRD3ErUQojoP
 X43sAPwP4Prb0NQTw68l5oSwOoIcuWb4GZBjxOPecDis/0K2ogD/WswDJ8qk3RAQ
 7XYGY8LuMdhwfcsx15TsuB/HAUie3QM=
 =wIGS
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/hdeller/tags/target-hppa-v3-pull-request' into staging

artist out of bounds fixes

# gpg: Signature made Wed 26 Aug 2020 22:09:55 BST
# gpg:                using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F
# gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown]
# gpg:                 aka "Helge Deller <deller@kernel.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4544 8228 2CD9 10DB EF3D  25F8 3E5F 3D04 A7A2 4603
#      Subkey fingerprint: BCE9 123E 1AD2 9F07 C049  BBDE F712 B510 A23A 0F5F

* remotes/hdeller/tags/target-hppa-v3-pull-request:
  hw/display/artist: Fix invalidation of lines near screen border
  hw/display/artist: Fix invalidation of lines in artist_draw_line()
  hw/display/artist: Unbreak size mismatch memory accesses
  hw/display/artist: Prevent out of VRAM buffer accesses
  Revert "hw/display/artist: Avoid drawing line when nothing to display"
  hw/display/artist: Refactor artist_rop8() to avoid buffer over-run
  hw/display/artist: Check offset in draw_line to avoid buffer over-run
  hw/hppa/lasi: Don't abort on invalid IMR value
  hw/display/artist.c: fix out of bounds check
  hw/hppa: Implement proper SeaBIOS version check
  seabios-hppa: Update to SeaBIOS hppa version 1
  hw/hppa: Sync hppa_hardware.h file with SeaBIOS sources

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-08-26 22:23:53 +01:00
commit 8e49197ca5
6 changed files with 149 additions and 77 deletions

View File

@ -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 {
@ -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);
@ -273,11 +278,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,
unsigned 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 >= buf->size) {
qemu_log_mask(LOG_GUEST_ERROR,
"rop8 offset:%u bufsize:%u\n", offset, buf->size);
return;
}
dst = buf->data + offset;
plane_mask = s->plane_mask & 0xff;
switch (op) {
case ARTIST_ROP_CLEAR:
@ -285,8 +299,7 @@ static void artist_rop8(ARTISTState *s, uint8_t *dst, uint8_t val)
break;
case ARTIST_ROP_COPY:
*dst &= ~plane_mask;
*dst |= val & plane_mask;
*dst = (*dst & ~plane_mask) | (val & plane_mask);
break;
case ARTIST_ROP_XOR:
@ -340,14 +353,14 @@ 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;
unsigned int 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) {
@ -356,8 +369,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;
}
@ -367,13 +379,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 +386,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, buf, off,
(data & 1) ? (s->plane_mask >> 24) : 0);
}
data >>= 1;
}
memory_region_set_dirty(&buf->mr, offset, pix_count);
@ -390,7 +398,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;
@ -398,7 +408,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, buf, off, data8[ROP8OFF(i)]);
}
}
}
memory_region_set_dirty(&buf->mr, offset, 3);
@ -420,16 +433,16 @@ 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) ||
(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);
}
}
}
@ -457,12 +470,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);
@ -474,6 +489,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 */
@ -500,24 +521,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->data + 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;
@ -548,23 +572,30 @@ 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);
}
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;
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;
uint8_t *p;
trace_artist_draw_line(x1, y1, x2, y2);
if ((x1 >= buf->width && x2 >= buf->width) ||
(y1 >= buf->height && y2 >= buf->height)) {
return;
}
if (update_start) {
s->vram_start = (x2 << 16) | y2;
}
@ -579,9 +610,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) {
@ -622,23 +650,23 @@ 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 {
unsigned 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) {
artist_invalidate_lines(buf, y, 1);
y += incy;
e += diago;
} else {
@ -646,6 +674,10 @@ static void draw_line(ARTISTState *s, int x1, int y1, int x2, int y2,
}
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)
@ -755,23 +787,24 @@ 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;
}
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);
}
}
}
@ -1125,7 +1158,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) {
@ -1146,18 +1179,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;
@ -1173,9 +1216,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);
@ -1199,20 +1245,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)

View File

@ -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

View File

@ -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"
@ -54,8 +55,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;
@ -172,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. */

View File

@ -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);

Binary file not shown.

@ -1 +1 @@
Subproject commit 1630ac7d65c4a09218cc677f1fa56cd5b3140447
Subproject commit 4ff7639e2b86d5775fa7d5cd0dbfa4d3a385a701