summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-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
4 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);