diff --git a/hw/display/artist.c b/hw/display/artist.c index 21b7fd1b44..1d877998b9 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -80,6 +80,7 @@ struct ARTISTState { uint32_t line_pattern_skip; uint32_t cursor_pos; + uint32_t cursor_cntrl; uint32_t cursor_height; uint32_t cursor_width; @@ -91,7 +92,6 @@ struct ARTISTState { uint32_t reg_300208; uint32_t reg_300218; - uint32_t cmap_bm_access; uint32_t dst_bm_access; uint32_t src_bm_access; uint32_t control_plane; @@ -134,7 +134,7 @@ typedef enum { PATTERN_LINE_START = 0x100ecc, LINE_SIZE = 0x100e04, LINE_END = 0x100e44, - CMAP_BM_ACCESS = 0x118000, + DST_SRC_BM_ACCESS = 0x118000, DST_BM_ACCESS = 0x118004, SRC_BM_ACCESS = 0x118008, CONTROL_PLANE = 0x11800c, @@ -176,7 +176,7 @@ static const char *artist_reg_name(uint64_t addr) REG_NAME(TRANSFER_DATA); REG_NAME(CONTROL_PLANE); REG_NAME(IMAGE_BITMAP_OP); - REG_NAME(CMAP_BM_ACCESS); + REG_NAME(DST_SRC_BM_ACCESS); REG_NAME(DST_BM_ACCESS); REG_NAME(SRC_BM_ACCESS); REG_NAME(CURSOR_POS); @@ -222,40 +222,14 @@ static void artist_invalidate_lines(struct vram_buffer *buf, } } -static int vram_write_pix_per_transfer(ARTISTState *s) -{ - if (s->cmap_bm_access) { - return 1 << ((s->cmap_bm_access >> 27) & 0x0f); - } else { - return 1 << ((s->dst_bm_access >> 27) & 0x0f); - } -} - -static int vram_pixel_length(ARTISTState *s) -{ - if (s->cmap_bm_access) { - return (s->cmap_bm_access >> 24) & 0x07; - } else { - return (s->dst_bm_access >> 24) & 0x07; - } -} - static int vram_write_bufidx(ARTISTState *s) { - if (s->cmap_bm_access) { - return (s->cmap_bm_access >> 12) & 0x0f; - } else { - return (s->dst_bm_access >> 12) & 0x0f; - } + return (s->dst_bm_access >> 12) & 0x0f; } static int vram_read_bufidx(ARTISTState *s) { - if (s->cmap_bm_access) { - return (s->cmap_bm_access >> 12) & 0x0f; - } else { - return (s->src_bm_access >> 12) & 0x0f; - } + return (s->src_bm_access >> 12) & 0x0f; } static struct vram_buffer *vram_read_buffer(ARTISTState *s) @@ -328,19 +302,42 @@ static void artist_get_cursor_pos(ARTISTState *s, int *x, int *y) { /* * Don't know whether these magic offset values are configurable via - * some register. They are the same for all resolutions, so don't - * bother about it. + * some register. They seem to be the same for all resolutions. + * The cursor values provided in the registers are: + * X-value: -295 (for HP-UX 11) and 338 (for HP-UX 10.20) up to 2265 + * Y-value: 1146 down to 0 + * The emulated Artist graphic is like a CRX graphic, and as such + * it's usually fixed at 1280x1024 pixels. + * Because of the maximum Y-value of 1146 you can not choose a higher + * vertical resolution on HP-UX (unless you disable the mouse). */ - *y = 0x47a - artist_get_y(s->cursor_pos); - *x = ((artist_get_x(s->cursor_pos) - 338) / 2); + static int offset = 338; + int lx; + + /* ignore if uninitialized */ + if (s->cursor_pos == 0) { + *x = *y = 0; + return; + } + + lx = artist_get_x(s->cursor_pos); + if (lx < offset) + offset = lx; + *x = (lx - offset) / 2; + + *y = 1146 - artist_get_y(s->cursor_pos); + + /* subtract cursor offset from cursor control register */ + *x -= (s->cursor_cntrl & 0xf0) >> 4; + *y -= (s->cursor_cntrl & 0x0f); if (*x > s->width) { - *x = 0; + *x = s->width; } if (*y > s->height) { - *y = 0; + *y = s->height; } } @@ -352,130 +349,6 @@ static void artist_invalidate_cursor(ARTISTState *s) y, s->cursor_height); } -static void vram_bit_write(ARTISTState *s, int posy, bool incr_x, - int size, uint32_t data) -{ - struct vram_buffer *buf; - uint32_t vram_bitmask = s->vram_bitmask; - int mask, i, pix_count, pix_length; - unsigned int posx, 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); - width = buf->width; - - if (s->cmap_bm_access) { - offset = s->vram_pos; - } else { - posx = ADDR_TO_X(s->vram_pos >> 2); - posy += ADDR_TO_Y(s->vram_pos >> 2); - offset = posy * width + posx; - } - - if (!buf->size || offset >= buf->size) { - return; - } - - p = buf->data; - - if (pix_count > size * 8) { - pix_count = size * 8; - } - - switch (pix_length) { - case 0: - if (s->image_bitmap_op & 0x20000000) { - data &= vram_bitmask; - } - - for (i = 0; i < pix_count; i++) { - 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); - break; - - case 3: - if (s->cmap_bm_access) { - if (offset + 3 < buf->size) { - *(uint32_t *)(p + offset) = data; - } - break; - } - data8 = (uint8_t *)&data; - - for (i = 3; i >= 0; i--) { - if (!(s->image_bitmap_op & 0x20000000) || - s->vram_bitmask & (1 << (28 + 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); - break; - - case 6: - switch (size) { - default: - case 4: - vram_bitmask = s->vram_bitmask; - break; - - case 2: - vram_bitmask = s->vram_bitmask >> 16; - break; - - case 1: - vram_bitmask = s->vram_bitmask >> 24; - break; - } - - 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, buf, offset + i, s->fg_color); - } else { - if (!(s->image_bitmap_op & 0x10000002)) { - artist_rop8(s, buf, offset + i, s->bg_color); - } - } - } - } - memory_region_set_dirty(&buf->mr, offset, pix_count); - break; - - default: - qemu_log_mask(LOG_UNIMP, "%s: unknown pixel length %d\n", - __func__, pix_length); - break; - } - - if (incr_x) { - if (s->cmap_bm_access) { - s->vram_pos += 4; - } else { - s->vram_pos += pix_count << 2; - } - } - - if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 || - vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) { - artist_invalidate_cursor(s); - } -} - static void block_move(ARTISTState *s, unsigned int source_x, unsigned int source_y, unsigned int dest_x, unsigned int dest_y, @@ -680,10 +553,11 @@ 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); + artist_invalidate_lines(buf, x1, x2 - x1); else - artist_invalidate_lines(buf, y, dx+1); + artist_invalidate_lines(buf, y1 > y2 ? y2 : y1, x2 - x1); } static void draw_line_pattern_start(ARTISTState *s) @@ -860,6 +734,151 @@ static void combine_write_reg(hwaddr addr, uint64_t val, int size, void *out) } } +static void artist_vram_write4(ARTISTState *s, struct vram_buffer *buf, + uint32_t offset, uint32_t data) +{ + int i; + int mask = s->vram_bitmask >> 28; + + for (i = 0; i < 4; i++) { + if (!(s->image_bitmap_op & 0x20000000) || (mask & 8)) { + artist_rop8(s, buf, offset + i, data >> 24); + data <<= 8; + mask <<= 1; + } + } + memory_region_set_dirty(&buf->mr, offset, 3); +} + +static void artist_vram_write32(ARTISTState *s, struct vram_buffer *buf, + uint32_t offset, int size, uint32_t data, + int fg, int bg) +{ + uint32_t mask, vram_bitmask = s->vram_bitmask >> ((4 - size) * 8); + int i, pix_count = size * 8; + + 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, buf, offset + i, fg); + } else { + if (!(s->image_bitmap_op & 0x10000002)) { + artist_rop8(s, buf, offset + i, bg); + } + } + } + } + memory_region_set_dirty(&buf->mr, offset, pix_count); +} + +static int get_vram_offset(ARTISTState *s, struct vram_buffer *buf, + int pos, int posy) +{ + unsigned int posx, width; + + width = buf->width; + posx = ADDR_TO_X(pos); + posy += ADDR_TO_Y(pos); + return posy * width + posx; +} + +static int vram_bit_write(ARTISTState *s, uint32_t pos, int posy, + uint32_t data, int size) +{ + struct vram_buffer *buf = vram_write_buffer(s); + + switch (s->dst_bm_access >> 16) { + case 0x3ba0: + case 0xbbe0: + artist_vram_write4(s, buf, pos, bswap32(data)); + pos += 4; + break; + + case 0x1360: /* linux */ + artist_vram_write4(s, buf, get_vram_offset(s, buf, pos, posy), data); + pos += 4; + break; + + case 0x13a0: + artist_vram_write4(s, buf, get_vram_offset(s, buf, pos >> 2, posy), + data); + pos += 16; + break; + + case 0x2ea0: + artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy), + size, data, s->fg_color, s->bg_color); + pos += 4; + break; + + case 0x28a0: + artist_vram_write32(s, buf, get_vram_offset(s, buf, pos >> 2, posy), + size, data, 1, 0); + pos += 4; + break; + + default: + qemu_log_mask(LOG_UNIMP, "%s: unknown dst bm access %08x\n", + __func__, s->dst_bm_access); + break; + } + + if (vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR1 || + vram_write_bufidx(s) == ARTIST_BUFFER_CURSOR2) { + artist_invalidate_cursor(s); + } + return pos; +} + +static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + ARTISTState *s = opaque; + s->vram_char_y = 0; + trace_artist_vram_write(size, addr, val); + vram_bit_write(opaque, addr, 0, val, size); +} + +static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size) +{ + ARTISTState *s = opaque; + struct vram_buffer *buf; + unsigned int offset; + uint64_t val; + + buf = vram_read_buffer(s); + if (!buf->size) { + return 0; + } + + offset = get_vram_offset(s, buf, addr >> 2, 0); + + if (offset > buf->size) { + return 0; + } + + switch (s->src_bm_access >> 16) { + case 0x3ba0: + val = *(uint32_t *)(buf->data + offset); + break; + + case 0x13a0: + case 0x2ea0: + val = bswap32(*(uint32_t *)(buf->data + offset)); + break; + + default: + qemu_log_mask(LOG_UNIMP, "%s: unknown src bm access %08x\n", + __func__, s->dst_bm_access); + val = -1ULL; + break; + } + trace_artist_vram_read(size, addr, val); + return val; +} + static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -886,12 +905,12 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, break; case VRAM_WRITE_INCR_Y: - vram_bit_write(s, s->vram_char_y++, false, size, val); + vram_bit_write(s, s->vram_pos, s->vram_char_y++, val, size); break; case VRAM_WRITE_INCR_X: case VRAM_WRITE_INCR_X2: - vram_bit_write(s, s->vram_char_y, true, size, val); + s->vram_pos = vram_bit_write(s, s->vram_pos, s->vram_char_y, val, size); break; case VRAM_IDX: @@ -993,18 +1012,17 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, combine_write_reg(addr, val, size, &s->plane_mask); break; - case CMAP_BM_ACCESS: - combine_write_reg(addr, val, size, &s->cmap_bm_access); + case DST_SRC_BM_ACCESS: + combine_write_reg(addr, val, size, &s->dst_bm_access); + combine_write_reg(addr, val, size, &s->src_bm_access); break; case DST_BM_ACCESS: combine_write_reg(addr, val, size, &s->dst_bm_access); - s->cmap_bm_access = 0; break; case SRC_BM_ACCESS: combine_write_reg(addr, val, size, &s->src_bm_access); - s->cmap_bm_access = 0; break; case CONTROL_PLANE: @@ -1034,6 +1052,7 @@ static void artist_reg_write(void *opaque, hwaddr addr, uint64_t val, break; case CURSOR_CTRL: + combine_write_reg(addr, val, size, &s->cursor_cntrl); break; case IMAGE_BITMAP_OP: @@ -1152,98 +1171,6 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size) return val; } -static void artist_vram_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - ARTISTState *s = opaque; - struct vram_buffer *buf; - unsigned int posy, posx; - unsigned int offset; - trace_artist_vram_write(size, addr, val); - - if (s->cmap_bm_access) { - buf = &s->vram_buffer[ARTIST_BUFFER_CMAP]; - if (addr + 3 < buf->size) { - *(uint32_t *)(buf->data + addr) = val; - } - return; - } - - buf = vram_write_buffer(s); - posy = ADDR_TO_Y(addr >> 2); - posx = ADDR_TO_X(addr >> 2); - - if (!buf->size) { - return; - } - - if (posy > buf->height || posx > buf->width) { - return; - } - - offset = posy * buf->width + posx; - if (offset >= buf->size) { - return; - } - - switch (size) { - case 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: - 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: - if (offset < buf->size) { - *(uint8_t *)(buf->data + offset) = val; - memory_region_set_dirty(&buf->mr, offset, 1); - } - break; - default: - break; - } -} - -static uint64_t artist_vram_read(void *opaque, hwaddr addr, unsigned size) -{ - ARTISTState *s = opaque; - struct vram_buffer *buf; - uint64_t val; - unsigned int posy, posx; - - if (s->cmap_bm_access) { - buf = &s->vram_buffer[ARTIST_BUFFER_CMAP]; - 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 val; - } - - buf = vram_read_buffer(s); - if (!buf->size) { - return 0; - } - - posy = ADDR_TO_Y(addr >> 2); - posx = ADDR_TO_X(addr >> 2); - - if (posy > buf->height || posx > buf->width) { - return 0; - } - - val = cpu_to_be32(*(uint32_t *)(buf->data + posy * buf->width + posx)); - trace_artist_vram_read(size, addr, posx, posy, val); - return val; -} - static const MemoryRegionOps artist_reg_ops = { .read = artist_reg_read, .write = artist_reg_write, @@ -1410,6 +1337,14 @@ static void artist_realizefn(DeviceState *dev, Error **errp) s->cursor_height = 32; s->cursor_width = 32; + /* + * These two registers are not initialized by seabios's STI implementation. + * Initialize them here to sane values so artist also works with older + * (not-fixed) seabios versions. + */ + s->image_bitmap_op = 0x23000300; + s->plane_mask = 0xff; + s->con = graphic_console_init(dev, 0, &artist_ops, s); qemu_console_resize(s->con, s->width, s->height); } @@ -1422,8 +1357,8 @@ static int vmstate_artist_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_artist = { .name = "artist", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .post_load = vmstate_artist_post_load, .fields = (VMStateField[]) { VMSTATE_UINT16(height, ARTISTState), @@ -1443,6 +1378,7 @@ static const VMStateDescription vmstate_artist = { VMSTATE_UINT32(line_end, ARTISTState), VMSTATE_UINT32(line_xy, ARTISTState), VMSTATE_UINT32(cursor_pos, ARTISTState), + VMSTATE_UINT32(cursor_cntrl, ARTISTState), VMSTATE_UINT32(cursor_height, ARTISTState), VMSTATE_UINT32(cursor_width, ARTISTState), VMSTATE_UINT32(plane_mask, ARTISTState), @@ -1450,7 +1386,6 @@ static const VMStateDescription vmstate_artist = { VMSTATE_UINT32(reg_300200, ARTISTState), VMSTATE_UINT32(reg_300208, ARTISTState), VMSTATE_UINT32(reg_300218, ARTISTState), - VMSTATE_UINT32(cmap_bm_access, ARTISTState), VMSTATE_UINT32(dst_bm_access, ARTISTState), VMSTATE_UINT32(src_bm_access, ARTISTState), VMSTATE_UINT32(control_plane, ARTISTState), diff --git a/hw/display/trace-events b/hw/display/trace-events index 3a7a2c957f..4a687d1b8e 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -140,10 +140,10 @@ ati_mm_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "% ati_mm_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 " %s <- 0x%"PRIx64 # artist.c -artist_reg_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s -> 0x%"PRIx64 -artist_reg_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s <- 0x%"PRIx64 -artist_vram_read(unsigned int size, uint64_t addr, int posx, int posy, uint64_t val) "%u 0x%"PRIx64 " %ux%u-> 0x%"PRIx64 -artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%"PRIx64 " <- 0x%"PRIx64 +artist_reg_read(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s -> 0x%08"PRIx64 +artist_reg_write(unsigned int size, uint64_t addr, const char *name, uint64_t val) "%u 0x%"PRIx64 "%s <- 0x%08"PRIx64 +artist_vram_read(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%08"PRIx64 " -> 0x%08"PRIx64 +artist_vram_write(unsigned int size, uint64_t addr, uint64_t val) "%u 0x%08"PRIx64 " <- 0x%08"PRIx64 artist_fill_window(unsigned int start_x, unsigned int start_y, unsigned int width, unsigned int height, uint32_t op, uint32_t ctlpln) "start=%ux%u length=%ux%u op=0x%08x ctlpln=0x%08x" artist_block_move(unsigned int start_x, unsigned int start_y, unsigned int dest_x, unsigned int dest_y, unsigned int width, unsigned int height) "source %ux%u -> dest %ux%u size %ux%u" artist_draw_line(unsigned int start_x, unsigned int start_y, unsigned int end_x, unsigned int end_y) "%ux%u %ux%u" diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h index bc258895c9..5edf577563 100644 --- a/hw/hppa/hppa_hardware.h +++ b/hw/hppa/hppa_hardware.h @@ -25,7 +25,7 @@ #define LASI_GFX_HPA 0xf8000000 #define ARTIST_FB_ADDR 0xf9000000 #define CPU_HPA 0xfffb0000 -#define MEMORY_HPA 0xfffbf000 +#define MEMORY_HPA 0xfffff000 #define PCI_HPA DINO_HPA /* PCI bus */ #define IDE_HPA 0xf9000000 /* Boot disc controller */ @@ -43,9 +43,10 @@ #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 HPPA_MAX_CPUS 16 /* 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) */ +#define PIM_STORAGE_SIZE 600 /* storage size of pdc_pim_toc_struct (64bit) */ #endif diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 2a46af5bc9..98b30e0395 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -17,6 +17,7 @@ #include "hw/timer/i8254.h" #include "hw/char/serial.h" #include "hw/net/lasi_82596.h" +#include "hw/nmi.h" #include "hppa_sys.h" #include "qemu/units.h" #include "qapi/error.h" @@ -355,6 +356,14 @@ static void hppa_machine_reset(MachineState *ms) cpu[0]->env.gr[19] = FW_CFG_IO_BASE; } +static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) +{ + CPUState *cs; + + CPU_FOREACH(cs) { + cpu_interrupt(cs, CPU_INTERRUPT_NMI); + } +} static void machine_hppa_machine_init(MachineClass *mc) { @@ -371,4 +380,28 @@ static void machine_hppa_machine_init(MachineClass *mc) mc->default_ram_id = "ram"; } -DEFINE_MACHINE("hppa", machine_hppa_machine_init) +static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + machine_hppa_machine_init(mc); + + NMIClass *nc = NMI_CLASS(oc); + nc->nmi_monitor_handler = hppa_nmi; +} + +static const TypeInfo machine_hppa_machine_init_typeinfo = { + .name = ("hppa" "-machine"), + .parent = "machine", + .class_init = machine_hppa_machine_init_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, +}; + +static void machine_hppa_machine_init_register_types(void) +{ + type_register_static(&machine_hppa_machine_init_typeinfo); +} + +type_init(machine_hppa_machine_init_register_types) diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img index a34a8c84f5..0ec2d96b8f 100644 Binary files a/pc-bios/hppa-firmware.img and b/pc-bios/hppa-firmware.img differ diff --git a/roms/seabios-hppa b/roms/seabios-hppa index b12acac4be..bf3404006f 160000 --- a/roms/seabios-hppa +++ b/roms/seabios-hppa @@ -1 +1 @@ -Subproject commit b12acac4be27b6d5d9fbe48c4be1286dcc245fbb +Subproject commit bf3404006fd2c832857eb57e6f853862f97dacea diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 23eb254228..37b763fca0 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -62,7 +62,7 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs, static bool hppa_cpu_has_work(CPUState *cs) { - return cs->interrupt_request & CPU_INTERRUPT_HARD; + return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); } static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 45fd338b02..93c119532a 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -69,6 +69,11 @@ #define EXCP_SYSCALL 30 #define EXCP_SYSCALL_LWS 31 +/* Emulated hardware TOC button */ +#define EXCP_TOC 32 /* TOC = Transfer of control (NMI) */ + +#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 /* TOC */ + /* Taken from Linux kernel: arch/parisc/include/asm/psw.h */ #define PSW_I 0x00000001 #define PSW_D 0x00000002 diff --git a/target/hppa/helper.h b/target/hppa/helper.h index 0a629ffa7c..fe8a9ce493 100644 --- a/target/hppa/helper.h +++ b/target/hppa/helper.h @@ -80,6 +80,7 @@ DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tr) #ifndef CONFIG_USER_ONLY DEF_HELPER_1(halt, noreturn, env) DEF_HELPER_1(reset, noreturn, env) +DEF_HELPER_1(getshadowregs, void, env) DEF_HELPER_1(rfi, void, env) DEF_HELPER_1(rfi_r, void, env) DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr) diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode index d4eefc0d48..c7a7e997f9 100644 --- a/target/hppa/insns.decode +++ b/target/hppa/insns.decode @@ -111,6 +111,7 @@ rfi_r 000000 ----- ----- --- 01100101 00000 # They are allocated from the unassigned instruction space. halt 1111 1111 1111 1101 1110 1010 1101 0000 reset 1111 1111 1111 1101 1110 1010 1101 0001 +getshadowregs 1111 1111 1111 1101 1110 1010 1101 0010 #### # Memory Management diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c index 13073ae2bd..f599dccfff 100644 --- a/target/hppa/int_helper.c +++ b/target/hppa/int_helper.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "hw/core/cpu.h" +#include "hw/hppa/hppa_hardware.h" #ifndef CONFIG_USER_ONLY static void eval_interrupt(HPPACPU *cpu) @@ -181,7 +182,14 @@ void hppa_cpu_do_interrupt(CPUState *cs) } /* step 7 */ - env->iaoq_f = env->cr[CR_IVA] + 32 * i; + if (i == EXCP_TOC) { + env->iaoq_f = FIRMWARE_START; + /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */ + env->gr[24] = env->cr_back[0]; + env->gr[25] = env->cr_back[1]; + } else { + env->iaoq_f = env->cr[CR_IVA] + 32 * i; + } env->iaoq_b = env->iaoq_f + 4; env->iasq_f = 0; env->iasq_b = 0; @@ -219,6 +227,7 @@ void hppa_cpu_do_interrupt(CPUState *cs) [EXCP_PER_INTERRUPT] = "performance monitor interrupt", [EXCP_SYSCALL] = "syscall", [EXCP_SYSCALL_LWS] = "syscall-lws", + [EXCP_TOC] = "TOC (transfer of control)", }; static int count; const char *name = NULL; @@ -248,6 +257,14 @@ bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request) HPPACPU *cpu = HPPA_CPU(cs); CPUHPPAState *env = &cpu->env; + if (interrupt_request & CPU_INTERRUPT_NMI) { + /* Raise TOC (NMI) interrupt */ + cpu_reset_interrupt(cs, CPU_INTERRUPT_NMI); + cs->exception_index = EXCP_TOC; + hppa_cpu_do_interrupt(cs); + return true; + } + /* If interrupts are requested and enabled, raise them. */ if ((env->psw & PSW_I) && (interrupt_request & CPU_INTERRUPT_HARD)) { cs->exception_index = EXCP_EXT_INTERRUPT; diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 1b86557d5d..b0dec4ebf4 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -694,7 +694,7 @@ void HELPER(rfi)(CPUHPPAState *env) cpu_hppa_put_psw(env, env->cr[CR_IPSW]); } -void HELPER(rfi_r)(CPUHPPAState *env) +void HELPER(getshadowregs)(CPUHPPAState *env) { env->gr[1] = env->shadow[0]; env->gr[8] = env->shadow[1]; @@ -703,6 +703,11 @@ void HELPER(rfi_r)(CPUHPPAState *env) env->gr[17] = env->shadow[4]; env->gr[24] = env->shadow[5]; env->gr[25] = env->shadow[6]; +} + +void HELPER(rfi_r)(CPUHPPAState *env) +{ + helper_getshadowregs(env); helper_rfi(env); } #endif diff --git a/target/hppa/translate.c b/target/hppa/translate.c index c6195590f8..5c0b1eb274 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -2393,6 +2393,16 @@ static bool trans_reset(DisasContext *ctx, arg_reset *a) #endif } +static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) +{ + CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); +#ifndef CONFIG_USER_ONLY + nullify_over(ctx); + gen_helper_getshadowregs(cpu_env); + return nullify_end(ctx); +#endif +} + static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) { if (a->m) {