Fixes and updates for hppa target

This patchset fixes some important bugs in the hppa artist graphics driver:
 - Fix artist graphics for HP-UX and Linux
 - Mouse cursor fixes for HP-UX
 - Fix draw_line() function on artist graphic
 
 and it adds new qemu features for hppa:
 - Allow up to 16 emulated CPUs (instead of 8)
 - Add support for an emulated TOC/NMI button
 
 A new Seabios-hppa firmware is included as well:
 - Update SeaBIOS-hppa to VERSION 3
 - New opt/hostid fw_cfg option to change hostid
 - Add opt/console fw_cfg option to select default console
 - Added 16x32 font to STI firmware
 
 Signed-off-by: Helge Deller <deller@gmx.de>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCYfrIogAKCRD3ErUQojoP
 X93ZAP9hqp/FCz/goH7Tpqce6FspHriJm6Ej2Rd7HxZWmh4bpQD/cMjY8qpcA/6r
 Nx4bgRPT6kCZwwLx7v2jZ2QsA2KaZAM=
 =c0qO
 -----END PGP SIGNATURE-----

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

Fixes and updates for hppa target

This patchset fixes some important bugs in the hppa artist graphics driver:
- Fix artist graphics for HP-UX and Linux
- Mouse cursor fixes for HP-UX
- Fix draw_line() function on artist graphic

and it adds new qemu features for hppa:
- Allow up to 16 emulated CPUs (instead of 8)
- Add support for an emulated TOC/NMI button

A new Seabios-hppa firmware is included as well:
- Update SeaBIOS-hppa to VERSION 3
- New opt/hostid fw_cfg option to change hostid
- Add opt/console fw_cfg option to select default console
- Added 16x32 font to STI firmware

Signed-off-by: Helge Deller <deller@gmx.de>

# gpg: Signature made Wed 02 Feb 2022 18:08:34 GMT
# 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/hppa-updates-pull-request:
  hw/display/artist: Fix draw_line() artefacts
  hw/display/artist: Mouse cursor fixes for HP-UX
  hw/display/artist: rewrite vram access mode handling
  hppa: Add support for an emulated TOC/NMI button.
  hw/hppa: Allow up to 16 emulated CPUs
  seabios-hppa: Update SeaBIOS-hppa to VERSION 3

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-02-02 19:54:30 +00:00
commit 8f3e5ce773
13 changed files with 283 additions and 275 deletions

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

@ -1 +1 @@
Subproject commit b12acac4be27b6d5d9fbe48c4be1286dcc245fbb
Subproject commit bf3404006fd2c832857eb57e6f853862f97dacea

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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