cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

macfb.c (22514B)


      1/*
      2 * QEMU Motorola 680x0 Macintosh Video Card Emulation
      3 *                 Copyright (c) 2012-2018 Laurent Vivier
      4 *
      5 * some parts from QEMU G364 framebuffer Emulator.
      6 *                 Copyright (c) 2007-2011 Herve Poussineau
      7 *
      8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9 * See the COPYING file in the top-level directory.
     10 *
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qemu/units.h"
     15#include "hw/sysbus.h"
     16#include "ui/console.h"
     17#include "ui/pixel_ops.h"
     18#include "hw/nubus/nubus.h"
     19#include "hw/display/macfb.h"
     20#include "qapi/error.h"
     21#include "hw/qdev-properties.h"
     22#include "migration/vmstate.h"
     23#include "trace.h"
     24
     25#define VIDEO_BASE 0x0
     26#define DAFB_BASE  0x00800000
     27
     28#define MACFB_PAGE_SIZE 4096
     29#define MACFB_VRAM_SIZE (4 * MiB)
     30
     31#define DAFB_MODE_VADDR1    0x0
     32#define DAFB_MODE_VADDR2    0x4
     33#define DAFB_MODE_CTRL1     0x8
     34#define DAFB_MODE_CTRL2     0xc
     35#define DAFB_MODE_SENSE     0x1c
     36#define DAFB_INTR_MASK      0x104
     37#define DAFB_INTR_STAT      0x108
     38#define DAFB_INTR_CLEAR     0x10c
     39#define DAFB_RESET          0x200
     40#define DAFB_LUT            0x213
     41
     42#define DAFB_INTR_VBL   0x4
     43
     44/* Vertical Blank period (60.15Hz) */
     45#define DAFB_INTR_VBL_PERIOD_NS 16625800
     46
     47/*
     48 * Quadra sense codes taken from Apple Technical Note HW26:
     49 * "Macintosh Quadra Built-In Video". The sense codes and
     50 * extended sense codes have different meanings:
     51 *
     52 * Sense:
     53 *    bit 2: SENSE2 (pin 10)
     54 *    bit 1: SENSE1 (pin 7)
     55 *    bit 0: SENSE0 (pin 4)
     56 *
     57 * 0 = pin tied to ground
     58 * 1 = pin unconnected
     59 *
     60 * Extended Sense:
     61 *    bit 2: pins 4-10
     62 *    bit 1: pins 10-7
     63 *    bit 0: pins 7-4
     64 *
     65 * 0 = pins tied together
     66 * 1 = pins unconnected
     67 *
     68 * Reads from the sense register appear to be active low, i.e. a 1 indicates
     69 * that the pin is tied to ground, a 0 indicates the pin is disconnected.
     70 *
     71 * Writes to the sense register appear to activate pulldowns i.e. a 1 enables
     72 * a pulldown on a particular pin.
     73 *
     74 * The MacOS toolbox appears to use a series of reads and writes to first
     75 * determine if extended sense is to be used, and then check which pins are
     76 * tied together in order to determine the display type.
     77 */
     78
     79typedef struct MacFbSense {
     80    uint8_t type;
     81    uint8_t sense;
     82    uint8_t ext_sense;
     83} MacFbSense;
     84
     85static MacFbSense macfb_sense_table[] = {
     86    { MACFB_DISPLAY_APPLE_21_COLOR, 0x0, 0 },
     87    { MACFB_DISPLAY_APPLE_PORTRAIT, 0x1, 0 },
     88    { MACFB_DISPLAY_APPLE_12_RGB, 0x2, 0 },
     89    { MACFB_DISPLAY_APPLE_2PAGE_MONO, 0x3, 0 },
     90    { MACFB_DISPLAY_NTSC_UNDERSCAN, 0x4, 0 },
     91    { MACFB_DISPLAY_NTSC_OVERSCAN, 0x4, 0 },
     92    { MACFB_DISPLAY_APPLE_12_MONO, 0x6, 0 },
     93    { MACFB_DISPLAY_APPLE_13_RGB, 0x6, 0 },
     94    { MACFB_DISPLAY_16_COLOR, 0x7, 0x3 },
     95    { MACFB_DISPLAY_PAL1_UNDERSCAN, 0x7, 0x0 },
     96    { MACFB_DISPLAY_PAL1_OVERSCAN, 0x7, 0x0 },
     97    { MACFB_DISPLAY_PAL2_UNDERSCAN, 0x7, 0x6 },
     98    { MACFB_DISPLAY_PAL2_OVERSCAN, 0x7, 0x6 },
     99    { MACFB_DISPLAY_VGA, 0x7, 0x5 },
    100    { MACFB_DISPLAY_SVGA, 0x7, 0x5 },
    101};
    102
    103static MacFbMode macfb_mode_table[] = {
    104    { MACFB_DISPLAY_VGA, 1, 0x100, 0x71e, 640, 480, 0x400, 0x1000 },
    105    { MACFB_DISPLAY_VGA, 2, 0x100, 0x70e, 640, 480, 0x400, 0x1000 },
    106    { MACFB_DISPLAY_VGA, 4, 0x100, 0x706, 640, 480, 0x400, 0x1000 },
    107    { MACFB_DISPLAY_VGA, 8, 0x100, 0x702, 640, 480, 0x400, 0x1000 },
    108    { MACFB_DISPLAY_VGA, 24, 0x100, 0x7ff, 640, 480, 0x1000, 0x1000 },
    109    { MACFB_DISPLAY_VGA, 1, 0xd0 , 0x70e, 800, 600, 0x340, 0xe00 },
    110    { MACFB_DISPLAY_VGA, 2, 0xd0 , 0x706, 800, 600, 0x340, 0xe00 },
    111    { MACFB_DISPLAY_VGA, 4, 0xd0 , 0x702, 800, 600, 0x340, 0xe00 },
    112    { MACFB_DISPLAY_VGA, 8, 0xd0,  0x700, 800, 600, 0x340, 0xe00 },
    113    { MACFB_DISPLAY_VGA, 24, 0x340, 0x100, 800, 600, 0xd00, 0xe00 },
    114    { MACFB_DISPLAY_APPLE_21_COLOR, 1, 0x90, 0x506, 1152, 870, 0x240, 0x80 },
    115    { MACFB_DISPLAY_APPLE_21_COLOR, 2, 0x90, 0x502, 1152, 870, 0x240, 0x80 },
    116    { MACFB_DISPLAY_APPLE_21_COLOR, 4, 0x90, 0x500, 1152, 870, 0x240, 0x80 },
    117    { MACFB_DISPLAY_APPLE_21_COLOR, 8, 0x120, 0x5ff, 1152, 870, 0x480, 0x80 },
    118};
    119
    120typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
    121                                  int width);
    122
    123static inline uint8_t macfb_read_byte(MacfbState *s, uint32_t addr)
    124{
    125    return s->vram[addr & s->vram_bit_mask];
    126}
    127
    128/* 1-bit color */
    129static void macfb_draw_line1(MacfbState *s, uint8_t *d, uint32_t addr,
    130                             int width)
    131{
    132    uint8_t r, g, b;
    133    int x;
    134
    135    for (x = 0; x < width; x++) {
    136        int bit = x & 7;
    137        int idx = (macfb_read_byte(s, addr) >> (7 - bit)) & 1;
    138        r = s->color_palette[idx * 3];
    139        g = s->color_palette[idx * 3 + 1];
    140        b = s->color_palette[idx * 3 + 2];
    141        addr += (bit == 7);
    142
    143        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    144        d += 4;
    145    }
    146}
    147
    148/* 2-bit color */
    149static void macfb_draw_line2(MacfbState *s, uint8_t *d, uint32_t addr,
    150                             int width)
    151{
    152    uint8_t r, g, b;
    153    int x;
    154
    155    for (x = 0; x < width; x++) {
    156        int bit = (x & 3);
    157        int idx = (macfb_read_byte(s, addr) >> ((3 - bit) << 1)) & 3;
    158        r = s->color_palette[idx * 3];
    159        g = s->color_palette[idx * 3 + 1];
    160        b = s->color_palette[idx * 3 + 2];
    161        addr += (bit == 3);
    162
    163        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    164        d += 4;
    165    }
    166}
    167
    168/* 4-bit color */
    169static void macfb_draw_line4(MacfbState *s, uint8_t *d, uint32_t addr,
    170                             int width)
    171{
    172    uint8_t r, g, b;
    173    int x;
    174
    175    for (x = 0; x < width; x++) {
    176        int bit = x & 1;
    177        int idx = (macfb_read_byte(s, addr) >> ((1 - bit) << 2)) & 15;
    178        r = s->color_palette[idx * 3];
    179        g = s->color_palette[idx * 3 + 1];
    180        b = s->color_palette[idx * 3 + 2];
    181        addr += (bit == 1);
    182
    183        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    184        d += 4;
    185    }
    186}
    187
    188/* 8-bit color */
    189static void macfb_draw_line8(MacfbState *s, uint8_t *d, uint32_t addr,
    190                             int width)
    191{
    192    uint8_t r, g, b;
    193    int x;
    194
    195    for (x = 0; x < width; x++) {
    196        r = s->color_palette[macfb_read_byte(s, addr) * 3];
    197        g = s->color_palette[macfb_read_byte(s, addr) * 3 + 1];
    198        b = s->color_palette[macfb_read_byte(s, addr) * 3 + 2];
    199        addr++;
    200
    201        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    202        d += 4;
    203    }
    204}
    205
    206/* 16-bit color */
    207static void macfb_draw_line16(MacfbState *s, uint8_t *d, uint32_t addr,
    208                              int width)
    209{
    210    uint8_t r, g, b;
    211    int x;
    212
    213    for (x = 0; x < width; x++) {
    214        uint16_t pixel;
    215        pixel = (macfb_read_byte(s, addr) << 8) | macfb_read_byte(s, addr + 1);
    216        r = ((pixel >> 10) & 0x1f) << 3;
    217        g = ((pixel >> 5) & 0x1f) << 3;
    218        b = (pixel & 0x1f) << 3;
    219        addr += 2;
    220
    221        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    222        d += 4;
    223    }
    224}
    225
    226/* 24-bit color */
    227static void macfb_draw_line24(MacfbState *s, uint8_t *d, uint32_t addr,
    228                              int width)
    229{
    230    uint8_t r, g, b;
    231    int x;
    232
    233    for (x = 0; x < width; x++) {
    234        r = macfb_read_byte(s, addr + 1);
    235        g = macfb_read_byte(s, addr + 2);
    236        b = macfb_read_byte(s, addr + 3);
    237        addr += 4;
    238
    239        *(uint32_t *)d = rgb_to_pixel32(r, g, b);
    240        d += 4;
    241    }
    242}
    243
    244
    245enum {
    246    MACFB_DRAW_LINE1,
    247    MACFB_DRAW_LINE2,
    248    MACFB_DRAW_LINE4,
    249    MACFB_DRAW_LINE8,
    250    MACFB_DRAW_LINE16,
    251    MACFB_DRAW_LINE24,
    252    MACFB_DRAW_LINE_NB,
    253};
    254
    255static macfb_draw_line_func * const
    256                              macfb_draw_line_table[MACFB_DRAW_LINE_NB] = {
    257    macfb_draw_line1,
    258    macfb_draw_line2,
    259    macfb_draw_line4,
    260    macfb_draw_line8,
    261    macfb_draw_line16,
    262    macfb_draw_line24,
    263};
    264
    265static int macfb_check_dirty(MacfbState *s, DirtyBitmapSnapshot *snap,
    266                             ram_addr_t addr, int len)
    267{
    268    return memory_region_snapshot_get_dirty(&s->mem_vram, snap, addr, len);
    269}
    270
    271static void macfb_draw_graphic(MacfbState *s)
    272{
    273    DisplaySurface *surface = qemu_console_surface(s->con);
    274    DirtyBitmapSnapshot *snap = NULL;
    275    ram_addr_t page;
    276    uint32_t v = 0;
    277    int y, ymin;
    278    int macfb_stride = s->mode->stride;
    279    macfb_draw_line_func *macfb_draw_line;
    280
    281    switch (s->depth) {
    282    case 1:
    283        v = MACFB_DRAW_LINE1;
    284        break;
    285    case 2:
    286        v = MACFB_DRAW_LINE2;
    287        break;
    288    case 4:
    289        v = MACFB_DRAW_LINE4;
    290        break;
    291    case 8:
    292        v = MACFB_DRAW_LINE8;
    293        break;
    294    case 16:
    295        v = MACFB_DRAW_LINE16;
    296        break;
    297    case 24:
    298        v = MACFB_DRAW_LINE24;
    299        break;
    300    }
    301
    302    macfb_draw_line = macfb_draw_line_table[v];
    303    assert(macfb_draw_line != NULL);
    304
    305    snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0x0,
    306                                             memory_region_size(&s->mem_vram),
    307                                             DIRTY_MEMORY_VGA);
    308
    309    ymin = -1;
    310    page = s->mode->offset;
    311    for (y = 0; y < s->height; y++, page += macfb_stride) {
    312        if (macfb_check_dirty(s, snap, page, macfb_stride)) {
    313            uint8_t *data_display;
    314
    315            data_display = surface_data(surface) + y * surface_stride(surface);
    316            macfb_draw_line(s, data_display, page, s->width);
    317
    318            if (ymin < 0) {
    319                ymin = y;
    320            }
    321        } else {
    322            if (ymin >= 0) {
    323                dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
    324                ymin = -1;
    325            }
    326        }
    327    }
    328
    329    if (ymin >= 0) {
    330        dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
    331    }
    332
    333    g_free(snap);
    334}
    335
    336static void macfb_invalidate_display(void *opaque)
    337{
    338    MacfbState *s = opaque;
    339
    340    memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
    341}
    342
    343static uint32_t macfb_sense_read(MacfbState *s)
    344{
    345    MacFbSense *macfb_sense;
    346    uint8_t sense;
    347
    348    assert(s->type < ARRAY_SIZE(macfb_sense_table));
    349    macfb_sense = &macfb_sense_table[s->type];
    350    if (macfb_sense->sense == 0x7) {
    351        /* Extended sense */
    352        sense = 0;
    353        if (!(macfb_sense->ext_sense & 1)) {
    354            /* Pins 7-4 together */
    355            if (~s->regs[DAFB_MODE_SENSE >> 2] & 3) {
    356                sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 3;
    357            }
    358        }
    359        if (!(macfb_sense->ext_sense & 2)) {
    360            /* Pins 10-7 together */
    361            if (~s->regs[DAFB_MODE_SENSE >> 2] & 6) {
    362                sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 6;
    363            }
    364        }
    365        if (!(macfb_sense->ext_sense & 4)) {
    366            /* Pins 4-10 together */
    367            if (~s->regs[DAFB_MODE_SENSE >> 2] & 5) {
    368                sense = (~s->regs[DAFB_MODE_SENSE >> 2] & 7) | 5;
    369            }
    370        }
    371    } else {
    372        /* Normal sense */
    373        sense = (~macfb_sense->sense & 7) |
    374                (~s->regs[DAFB_MODE_SENSE >> 2] & 7);
    375    }
    376
    377    trace_macfb_sense_read(sense);
    378    return sense;
    379}
    380
    381static void macfb_sense_write(MacfbState *s, uint32_t val)
    382{
    383    s->regs[DAFB_MODE_SENSE >> 2] = val;
    384
    385    trace_macfb_sense_write(val);
    386    return;
    387}
    388
    389static void macfb_update_mode(MacfbState *s)
    390{
    391    s->width = s->mode->width;
    392    s->height = s->mode->height;
    393    s->depth = s->mode->depth;
    394
    395    trace_macfb_update_mode(s->width, s->height, s->depth);
    396    macfb_invalidate_display(s);
    397}
    398
    399static void macfb_mode_write(MacfbState *s)
    400{
    401    MacFbMode *macfb_mode;
    402    int i;
    403
    404    for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
    405        macfb_mode = &macfb_mode_table[i];
    406
    407        if (s->type != macfb_mode->type) {
    408            continue;
    409        }
    410
    411        if ((s->regs[DAFB_MODE_CTRL1 >> 2] & 0xff) ==
    412             (macfb_mode->mode_ctrl1 & 0xff) &&
    413            (s->regs[DAFB_MODE_CTRL2 >> 2] & 0xff) ==
    414             (macfb_mode->mode_ctrl2 & 0xff)) {
    415            s->mode = macfb_mode;
    416            macfb_update_mode(s);
    417            break;
    418        }
    419    }
    420}
    421
    422static MacFbMode *macfb_find_mode(MacfbDisplayType display_type,
    423                                  uint16_t width, uint16_t height,
    424                                  uint8_t depth)
    425{
    426    MacFbMode *macfb_mode;
    427    int i;
    428
    429    for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
    430        macfb_mode = &macfb_mode_table[i];
    431
    432        if (display_type == macfb_mode->type && width == macfb_mode->width &&
    433                height == macfb_mode->height && depth == macfb_mode->depth) {
    434            return macfb_mode;
    435        }
    436    }
    437
    438    return NULL;
    439}
    440
    441static gchar *macfb_mode_list(void)
    442{
    443    gchar *list = NULL;
    444    gchar *mode;
    445    MacFbMode *macfb_mode;
    446    int i;
    447
    448    for (i = 0; i < ARRAY_SIZE(macfb_mode_table); i++) {
    449        macfb_mode = &macfb_mode_table[i];
    450
    451        mode = g_strdup_printf("    %dx%dx%d\n", macfb_mode->width,
    452                               macfb_mode->height, macfb_mode->depth);
    453        list = g_strconcat(mode, list, NULL);
    454        g_free(mode);
    455    }
    456
    457    return list;
    458}
    459
    460
    461static void macfb_update_display(void *opaque)
    462{
    463    MacfbState *s = opaque;
    464    DisplaySurface *surface = qemu_console_surface(s->con);
    465
    466    qemu_flush_coalesced_mmio_buffer();
    467
    468    if (s->width == 0 || s->height == 0) {
    469        return;
    470    }
    471
    472    if (s->width != surface_width(surface) ||
    473        s->height != surface_height(surface)) {
    474        qemu_console_resize(s->con, s->width, s->height);
    475    }
    476
    477    macfb_draw_graphic(s);
    478}
    479
    480static void macfb_update_irq(MacfbState *s)
    481{
    482    uint32_t irq_state = s->irq_state & s->irq_mask;
    483
    484    if (irq_state) {
    485        qemu_irq_raise(s->irq);
    486    } else {
    487        qemu_irq_lower(s->irq);
    488    }
    489}
    490
    491static int64_t macfb_next_vbl(void)
    492{
    493    return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + DAFB_INTR_VBL_PERIOD_NS) /
    494            DAFB_INTR_VBL_PERIOD_NS * DAFB_INTR_VBL_PERIOD_NS;
    495}
    496
    497static void macfb_vbl_timer(void *opaque)
    498{
    499    MacfbState *s = opaque;
    500    int64_t next_vbl;
    501
    502    s->irq_state |= DAFB_INTR_VBL;
    503    macfb_update_irq(s);
    504
    505    /* 60 Hz irq */
    506    next_vbl = macfb_next_vbl();
    507    timer_mod(s->vbl_timer, next_vbl);
    508}
    509
    510static void macfb_reset(MacfbState *s)
    511{
    512    int i;
    513
    514    s->palette_current = 0;
    515    for (i = 0; i < 256; i++) {
    516        s->color_palette[i * 3] = 255 - i;
    517        s->color_palette[i * 3 + 1] = 255 - i;
    518        s->color_palette[i * 3 + 2] = 255 - i;
    519    }
    520    memset(s->vram, 0, MACFB_VRAM_SIZE);
    521    macfb_invalidate_display(s);
    522}
    523
    524static uint64_t macfb_ctrl_read(void *opaque,
    525                                hwaddr addr,
    526                                unsigned int size)
    527{
    528    MacfbState *s = opaque;
    529    uint64_t val = 0;
    530
    531    switch (addr) {
    532    case DAFB_MODE_VADDR1:
    533    case DAFB_MODE_VADDR2:
    534    case DAFB_MODE_CTRL1:
    535    case DAFB_MODE_CTRL2:
    536        val = s->regs[addr >> 2];
    537        break;
    538    case DAFB_INTR_STAT:
    539        val = s->irq_state;
    540        break;
    541    case DAFB_MODE_SENSE:
    542        val = macfb_sense_read(s);
    543        break;
    544    }
    545
    546    trace_macfb_ctrl_read(addr, val, size);
    547    return val;
    548}
    549
    550static void macfb_ctrl_write(void *opaque,
    551                             hwaddr addr,
    552                             uint64_t val,
    553                             unsigned int size)
    554{
    555    MacfbState *s = opaque;
    556    int64_t next_vbl;
    557
    558    switch (addr) {
    559    case DAFB_MODE_VADDR1:
    560    case DAFB_MODE_VADDR2:
    561        s->regs[addr >> 2] = val;
    562        break;
    563    case DAFB_MODE_CTRL1 ... DAFB_MODE_CTRL1 + 3:
    564    case DAFB_MODE_CTRL2 ... DAFB_MODE_CTRL2 + 3:
    565        s->regs[addr >> 2] = val;
    566        if (val) {
    567            macfb_mode_write(s);
    568        }
    569        break;
    570    case DAFB_MODE_SENSE:
    571        macfb_sense_write(s, val);
    572        break;
    573    case DAFB_INTR_MASK:
    574        s->irq_mask = val;
    575        if (val & DAFB_INTR_VBL) {
    576            next_vbl = macfb_next_vbl();
    577            timer_mod(s->vbl_timer, next_vbl);
    578        } else {
    579            timer_del(s->vbl_timer);
    580        }
    581        break;
    582    case DAFB_INTR_CLEAR:
    583        s->irq_state &= ~DAFB_INTR_VBL;
    584        macfb_update_irq(s);
    585        break;
    586    case DAFB_RESET:
    587        s->palette_current = 0;
    588        s->irq_state &= ~DAFB_INTR_VBL;
    589        macfb_update_irq(s);
    590        break;
    591    case DAFB_LUT:
    592        s->color_palette[s->palette_current] = val;
    593        s->palette_current = (s->palette_current + 1) %
    594                             ARRAY_SIZE(s->color_palette);
    595        if (s->palette_current % 3) {
    596            macfb_invalidate_display(s);
    597        }
    598        break;
    599    }
    600
    601    trace_macfb_ctrl_write(addr, val, size);
    602}
    603
    604static const MemoryRegionOps macfb_ctrl_ops = {
    605    .read = macfb_ctrl_read,
    606    .write = macfb_ctrl_write,
    607    .endianness = DEVICE_BIG_ENDIAN,
    608    .impl.min_access_size = 1,
    609    .impl.max_access_size = 4,
    610};
    611
    612static int macfb_post_load(void *opaque, int version_id)
    613{
    614    macfb_mode_write(opaque);
    615    return 0;
    616}
    617
    618static const VMStateDescription vmstate_macfb = {
    619    .name = "macfb",
    620    .version_id = 1,
    621    .minimum_version_id = 1,
    622    .minimum_version_id_old = 1,
    623    .post_load = macfb_post_load,
    624    .fields = (VMStateField[]) {
    625        VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
    626        VMSTATE_UINT32(palette_current, MacfbState),
    627        VMSTATE_UINT32_ARRAY(regs, MacfbState, MACFB_NUM_REGS),
    628        VMSTATE_END_OF_LIST()
    629    }
    630};
    631
    632static const GraphicHwOps macfb_ops = {
    633    .invalidate = macfb_invalidate_display,
    634    .gfx_update = macfb_update_display,
    635};
    636
    637static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
    638{
    639    DisplaySurface *surface;
    640
    641    s->mode = macfb_find_mode(s->type, s->width, s->height, s->depth);
    642    if (!s->mode) {
    643        gchar *list;
    644        error_setg(errp, "unknown display mode: width %d, height %d, depth %d",
    645                   s->width, s->height, s->depth);
    646        list =  macfb_mode_list();
    647        error_append_hint(errp, "Available modes:\n%s", list);
    648        g_free(list);
    649
    650        return false;
    651    }
    652
    653    s->con = graphic_console_init(dev, 0, &macfb_ops, s);
    654    surface = qemu_console_surface(s->con);
    655
    656    if (surface_bits_per_pixel(surface) != 32) {
    657        error_setg(errp, "unknown host depth %d",
    658                   surface_bits_per_pixel(surface));
    659        return false;
    660    }
    661
    662    memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &macfb_ctrl_ops, s,
    663                          "macfb-ctrl", 0x1000);
    664
    665    memory_region_init_ram(&s->mem_vram, OBJECT(dev), "macfb-vram",
    666                           MACFB_VRAM_SIZE, &error_abort);
    667    s->vram = memory_region_get_ram_ptr(&s->mem_vram);
    668    s->vram_bit_mask = MACFB_VRAM_SIZE - 1;
    669    memory_region_set_coalescing(&s->mem_vram);
    670
    671    s->vbl_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, macfb_vbl_timer, s);
    672    macfb_update_mode(s);
    673    return true;
    674}
    675
    676static void macfb_sysbus_realize(DeviceState *dev, Error **errp)
    677{
    678    MacfbSysBusState *s = MACFB(dev);
    679    MacfbState *ms = &s->macfb;
    680
    681    if (!macfb_common_realize(dev, ms, errp)) {
    682        return;
    683    }
    684
    685    sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_ctrl);
    686    sysbus_init_mmio(SYS_BUS_DEVICE(s), &ms->mem_vram);
    687
    688    qdev_init_gpio_out(dev, &ms->irq, 1);
    689}
    690
    691static void macfb_nubus_set_irq(void *opaque, int n, int level)
    692{
    693    MacfbNubusState *s = NUBUS_MACFB(opaque);
    694    NubusDevice *nd = NUBUS_DEVICE(s);
    695
    696    nubus_set_irq(nd, level);
    697}
    698
    699static void macfb_nubus_realize(DeviceState *dev, Error **errp)
    700{
    701    NubusDevice *nd = NUBUS_DEVICE(dev);
    702    MacfbNubusState *s = NUBUS_MACFB(dev);
    703    MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
    704    MacfbState *ms = &s->macfb;
    705
    706    ndc->parent_realize(dev, errp);
    707    if (*errp) {
    708        return;
    709    }
    710
    711    if (!macfb_common_realize(dev, ms, errp)) {
    712        return;
    713    }
    714
    715    memory_region_add_subregion(&nd->slot_mem, DAFB_BASE, &ms->mem_ctrl);
    716    memory_region_add_subregion(&nd->slot_mem, VIDEO_BASE, &ms->mem_vram);
    717
    718    ms->irq = qemu_allocate_irq(macfb_nubus_set_irq, s, 0);
    719}
    720
    721static void macfb_nubus_unrealize(DeviceState *dev)
    722{
    723    MacfbNubusState *s = NUBUS_MACFB(dev);
    724    MacfbNubusDeviceClass *ndc = NUBUS_MACFB_GET_CLASS(dev);
    725    MacfbState *ms = &s->macfb;
    726
    727    ndc->parent_unrealize(dev);
    728
    729    qemu_free_irq(ms->irq);
    730}
    731
    732static void macfb_sysbus_reset(DeviceState *d)
    733{
    734    MacfbSysBusState *s = MACFB(d);
    735    macfb_reset(&s->macfb);
    736}
    737
    738static void macfb_nubus_reset(DeviceState *d)
    739{
    740    MacfbNubusState *s = NUBUS_MACFB(d);
    741    macfb_reset(&s->macfb);
    742}
    743
    744static Property macfb_sysbus_properties[] = {
    745    DEFINE_PROP_UINT32("width", MacfbSysBusState, macfb.width, 640),
    746    DEFINE_PROP_UINT32("height", MacfbSysBusState, macfb.height, 480),
    747    DEFINE_PROP_UINT8("depth", MacfbSysBusState, macfb.depth, 8),
    748    DEFINE_PROP_UINT8("display", MacfbSysBusState, macfb.type,
    749                      MACFB_DISPLAY_VGA),
    750    DEFINE_PROP_END_OF_LIST(),
    751};
    752
    753static Property macfb_nubus_properties[] = {
    754    DEFINE_PROP_UINT32("width", MacfbNubusState, macfb.width, 640),
    755    DEFINE_PROP_UINT32("height", MacfbNubusState, macfb.height, 480),
    756    DEFINE_PROP_UINT8("depth", MacfbNubusState, macfb.depth, 8),
    757    DEFINE_PROP_UINT8("display", MacfbNubusState, macfb.type,
    758                      MACFB_DISPLAY_VGA),
    759    DEFINE_PROP_END_OF_LIST(),
    760};
    761
    762static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
    763{
    764    DeviceClass *dc = DEVICE_CLASS(klass);
    765
    766    dc->realize = macfb_sysbus_realize;
    767    dc->desc = "SysBus Macintosh framebuffer";
    768    dc->reset = macfb_sysbus_reset;
    769    dc->vmsd = &vmstate_macfb;
    770    device_class_set_props(dc, macfb_sysbus_properties);
    771}
    772
    773static void macfb_nubus_class_init(ObjectClass *klass, void *data)
    774{
    775    DeviceClass *dc = DEVICE_CLASS(klass);
    776    MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass);
    777
    778    device_class_set_parent_realize(dc, macfb_nubus_realize,
    779                                    &ndc->parent_realize);
    780    device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
    781                                      &ndc->parent_unrealize);
    782    dc->desc = "Nubus Macintosh framebuffer";
    783    dc->reset = macfb_nubus_reset;
    784    dc->vmsd = &vmstate_macfb;
    785    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    786    device_class_set_props(dc, macfb_nubus_properties);
    787}
    788
    789static TypeInfo macfb_sysbus_info = {
    790    .name          = TYPE_MACFB,
    791    .parent        = TYPE_SYS_BUS_DEVICE,
    792    .instance_size = sizeof(MacfbSysBusState),
    793    .class_init    = macfb_sysbus_class_init,
    794};
    795
    796static TypeInfo macfb_nubus_info = {
    797    .name          = TYPE_NUBUS_MACFB,
    798    .parent        = TYPE_NUBUS_DEVICE,
    799    .instance_size = sizeof(MacfbNubusState),
    800    .class_init    = macfb_nubus_class_init,
    801    .class_size    = sizeof(MacfbNubusDeviceClass),
    802};
    803
    804static void macfb_register_types(void)
    805{
    806    type_register_static(&macfb_sysbus_info);
    807    type_register_static(&macfb_nubus_info);
    808}
    809
    810type_init(macfb_register_types)