aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-08-26 22:23:53 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-08-26 22:23:53 +0100
commit8e49197ca5e76fdb8928833b2649ef13fc5aab2f (patch)
tree7ee4b595d666480a8c237b154feea90f81620646
parent25f6dc28a3a8dd231c2c092a0e65bd796353c769 (diff)
parent2f8cd515477edab1cbf38ecbdbfa2cac13ce1550 (diff)
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>
-rw-r--r--hw/display/artist.c186
-rw-r--r--hw/hppa/hppa_hardware.h6
-rw-r--r--hw/hppa/lasi.c10
-rw-r--r--hw/hppa/machine.c22
-rw-r--r--pc-bios/hppa-firmware.imgbin766136 -> 783192 bytes
m---------roms/seabios-hppa0
6 files changed, 148 insertions, 76 deletions
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 6261bfe65b..71982559c6 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 {
@@ -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)
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..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"
@@ -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. */
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);
diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img
index 82d98b1353..f0f8d0e164 100644
--- a/pc-bios/hppa-firmware.img
+++ b/pc-bios/hppa-firmware.img
Binary files differ
diff --git a/roms/seabios-hppa b/roms/seabios-hppa
-Subproject 1630ac7d65c4a09218cc677f1fa56cd5b314044
+Subproject 4ff7639e2b86d5775fa7d5cd0dbfa4d3a385a70