Commit df1ac44e authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-next-20151112' into staging



ppc patch queue -2015-11-12

Highlights:
   - A number of fixes for MacOS 9 compatibility based on the old MOL
     (Mac-On-Linux) code and a GSoC project.
   - Cleaner and more general way of handling register access from the
     monitor

# gpg: Signature made Thu 12 Nov 2015 04:33:26 GMT using RSA key ID 20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-next-20151112:
  monitor/target-ppc: Define target_get_monitor_def
  cuda.c: add delay to setting of SR_INT bit
  cuda.c: fix T2 timer and enable its interrupt
  cuda.c: rename get_counter() state variable from s to ti for consistency
  cuda.c: refactor get_tb() so that the time can be passed in
  cuda.c: add defines for CUDA registers
  cuda.c: fix CUDA SR interrupt clearing
  cuda.c: implement dummy IIC access commands
  cuda.c: implement simple CUDA_GET_6805_ADDR command
  cuda.c: fix CUDA_PACKET response packet format
  cuda.c: fix CUDA ADB error packet format
  PPC: mac99: Always add USB controller
  PPC: Fix lswx bounds checks
  PPC: Allow Rc bit to be set on mtspr

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents fd717e78 0a9516c2
Loading
Loading
Loading
Loading
+157 −89
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@
#define IER_SET		0x80		/* set bits in IER */
#define IER_CLR		0		/* clear bits in IER */
#define SR_INT		0x04		/* Shift register full/empty */
#define SR_DATA_INT	0x08
#define SR_CLOCK_INT	0x10
#define T1_INT          0x40            /* Timer 1 interrupt */
#define T2_INT          0x20            /* Timer 2 interrupt */

@@ -108,6 +110,24 @@
/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
#define RTC_OFFSET                      2082844800

/* CUDA registers */
#define CUDA_REG_B       0x00
#define CUDA_REG_A       0x01
#define CUDA_REG_DIRB    0x02
#define CUDA_REG_DIRA    0x03
#define CUDA_REG_T1CL    0x04
#define CUDA_REG_T1CH    0x05
#define CUDA_REG_T1LL    0x06
#define CUDA_REG_T1LH    0x07
#define CUDA_REG_T2CL    0x08
#define CUDA_REG_T2CH    0x09
#define CUDA_REG_SR      0x0a
#define CUDA_REG_ACR     0x0b
#define CUDA_REG_PCR     0x0c
#define CUDA_REG_IFR     0x0d
#define CUDA_REG_IER     0x0e
#define CUDA_REG_ANH     0x0f

static void cuda_update(CUDAState *s);
static void cuda_receive_packet_from_host(CUDAState *s,
                                          const uint8_t *data, int len);
@@ -116,47 +136,48 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti,

static void cuda_update_irq(CUDAState *s)
{
    if (s->ifr & s->ier & (SR_INT | T1_INT)) {
    if (s->ifr & s->ier & (SR_INT | T1_INT | T2_INT)) {
        qemu_irq_raise(s->irq);
    } else {
        qemu_irq_lower(s->irq);
    }
}

static uint64_t get_tb(uint64_t freq)
static uint64_t get_tb(uint64_t time, uint64_t freq)
{
    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
                    freq, get_ticks_per_sec());
    return muldiv64(time, freq, get_ticks_per_sec());
}

static unsigned int get_counter(CUDATimer *s)
static unsigned int get_counter(CUDATimer *ti)
{
    int64_t d;
    unsigned int counter;
    uint64_t tb_diff;
    uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);

    /* Reverse of the tb calculation algorithm that Mac OS X uses on bootup. */
    tb_diff = get_tb(s->frequency) - s->load_time;
    d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24);
    tb_diff = get_tb(current_time, ti->frequency) - ti->load_time;
    d = (tb_diff * 0xBF401675E5DULL) / (ti->frequency << 24);

    if (s->index == 0) {
    if (ti->index == 0) {
        /* the timer goes down from latch to -1 (period of latch + 2) */
        if (d <= (s->counter_value + 1)) {
            counter = (s->counter_value - d) & 0xffff;
        if (d <= (ti->counter_value + 1)) {
            counter = (ti->counter_value - d) & 0xffff;
        } else {
            counter = (d - (s->counter_value + 1)) % (s->latch + 2);
            counter = (s->latch - counter) & 0xffff;
            counter = (d - (ti->counter_value + 1)) % (ti->latch + 2);
            counter = (ti->latch - counter) & 0xffff;
        }
    } else {
        counter = (s->counter_value - d) & 0xffff;
        counter = (ti->counter_value - d) & 0xffff;
    }
    return counter;
}

static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
{
    CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
    ti->load_time = get_tb(s->frequency);
    CUDA_DPRINTF("T%d.counter=%d\n", 1 + ti->index, val);
    ti->load_time = get_tb(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
                           s->frequency);
    ti->counter_value = val;
    cuda_timer_update(s, ti, ti->load_time);
}
@@ -199,7 +220,7 @@ static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
{
    if (!ti->timer)
        return;
    if ((s->acr & T1MODE) != T1MODE_CONT) {
    if (ti->index == 0 && (s->acr & T1MODE) != T1MODE_CONT) {
        timer_del(ti->timer);
    } else {
        ti->next_irq_time = get_next_irq_time(ti, current_time);
@@ -217,6 +238,41 @@ static void cuda_timer1(void *opaque)
    cuda_update_irq(s);
}

static void cuda_timer2(void *opaque)
{
    CUDAState *s = opaque;
    CUDATimer *ti = &s->timers[1];

    cuda_timer_update(s, ti, ti->next_irq_time);
    s->ifr |= T2_INT;
    cuda_update_irq(s);
}

static void cuda_set_sr_int(void *opaque)
{
    CUDAState *s = opaque;

    CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__);
    s->ifr |= SR_INT;
    cuda_update_irq(s);
}

static void cuda_delay_set_sr_int(CUDAState *s)
{
    int64_t expire;

    if (s->dirb == 0xff) {
        /* Not in Mac OS, fire the IRQ directly */
        cuda_set_sr_int(s);
        return;
    }

    CUDA_DPRINTF("CUDA: %s:%d\n", __func__, __LINE__);

    expire = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 300 * SCALE_US;
    timer_mod(s->sr_delay_timer, expire);
}

static uint32_t cuda_readb(void *opaque, hwaddr addr)
{
    CUDAState *s = opaque;
@@ -224,66 +280,68 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr)

    addr = (addr >> 9) & 0xf;
    switch(addr) {
    case 0:
    case CUDA_REG_B:
        val = s->b;
        break;
    case 1:
    case CUDA_REG_A:
        val = s->a;
        break;
    case 2:
    case CUDA_REG_DIRB:
        val = s->dirb;
        break;
    case 3:
    case CUDA_REG_DIRA:
        val = s->dira;
        break;
    case 4:
    case CUDA_REG_T1CL:
        val = get_counter(&s->timers[0]) & 0xff;
        s->ifr &= ~T1_INT;
        cuda_update_irq(s);
        break;
    case 5:
    case CUDA_REG_T1CH:
        val = get_counter(&s->timers[0]) >> 8;
        cuda_update_irq(s);
        break;
    case 6:
    case CUDA_REG_T1LL:
        val = s->timers[0].latch & 0xff;
        break;
    case 7:
    case CUDA_REG_T1LH:
        /* XXX: check this */
        val = (s->timers[0].latch >> 8) & 0xff;
        break;
    case 8:
    case CUDA_REG_T2CL:
        val = get_counter(&s->timers[1]) & 0xff;
        s->ifr &= ~T2_INT;
        cuda_update_irq(s);
        break;
    case 9:
    case CUDA_REG_T2CH:
        val = get_counter(&s->timers[1]) >> 8;
        break;
    case 10:
    case CUDA_REG_SR:
        val = s->sr;
        s->ifr &= ~SR_INT;
        s->ifr &= ~(SR_INT | SR_CLOCK_INT | SR_DATA_INT);
        cuda_update_irq(s);
        break;
    case 11:
    case CUDA_REG_ACR:
        val = s->acr;
        break;
    case 12:
    case CUDA_REG_PCR:
        val = s->pcr;
        break;
    case 13:
    case CUDA_REG_IFR:
        val = s->ifr;
        if (s->ifr & s->ier)
        if (s->ifr & s->ier) {
            val |= 0x80;
        }
        break;
    case 14:
    case CUDA_REG_IER:
        val = s->ier | 0x80;
        break;
    default:
    case 15:
    case CUDA_REG_ANH:
        val = s->anh;
        break;
    }
    if (addr != 13 || val != 0) {
    if (addr != CUDA_REG_IFR || val != 0) {
        CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
    }

@@ -298,61 +356,65 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val)
    CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);

    switch(addr) {
    case 0:
    case CUDA_REG_B:
        s->b = val;
        cuda_update(s);
        break;
    case 1:
    case CUDA_REG_A:
        s->a = val;
        break;
    case 2:
    case CUDA_REG_DIRB:
        s->dirb = val;
        break;
    case 3:
    case CUDA_REG_DIRA:
        s->dira = val;
        break;
    case 4:
    case CUDA_REG_T1CL:
        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
        cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
        break;
    case 5:
    case CUDA_REG_T1CH:
        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
        s->ifr &= ~T1_INT;
        set_counter(s, &s->timers[0], s->timers[0].latch);
        break;
    case 6:
    case CUDA_REG_T1LL:
        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
        cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
        break;
    case 7:
    case CUDA_REG_T1LH:
        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
        s->ifr &= ~T1_INT;
        cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
        break;
    case 8:
        s->timers[1].latch = val;
        set_counter(s, &s->timers[1], val);
    case CUDA_REG_T2CL:
        s->timers[1].latch = (s->timers[1].latch & 0xff00) | val;
        break;
    case 9:
        set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
    case CUDA_REG_T2CH:
        /* To ensure T2 generates an interrupt on zero crossing with the
           common timer code, write the value directly from the latch to
           the counter */
        s->timers[1].latch = (s->timers[1].latch & 0xff) | (val << 8);
        s->ifr &= ~T2_INT;
        set_counter(s, &s->timers[1], s->timers[1].latch);
        break;
    case 10:
    case CUDA_REG_SR:
        s->sr = val;
        break;
    case 11:
    case CUDA_REG_ACR:
        s->acr = val;
        cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
        cuda_update(s);
        break;
    case 12:
    case CUDA_REG_PCR:
        s->pcr = val;
        break;
    case 13:
    case CUDA_REG_IFR:
        /* reset bits */
        s->ifr &= ~val;
        cuda_update_irq(s);
        break;
    case 14:
    case CUDA_REG_IER:
        if (val & IER_SET) {
            /* set bits */
            s->ier |= val & 0x7f;
@@ -363,7 +425,7 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val)
        cuda_update_irq(s);
        break;
    default:
    case 15:
    case CUDA_REG_ANH:
        s->anh = val;
        break;
    }
@@ -384,8 +446,7 @@ static void cuda_update(CUDAState *s)
                if (s->data_out_index < sizeof(s->data_out)) {
                    CUDA_DPRINTF("send: %02x\n", s->sr);
                    s->data_out[s->data_out_index++] = s->sr;
                    s->ifr |= SR_INT;
                    cuda_update_irq(s);
                    cuda_delay_set_sr_int(s);
                }
            }
        } else {
@@ -398,8 +459,7 @@ static void cuda_update(CUDAState *s)
                    if (s->data_in_index >= s->data_in_size) {
                        s->b = (s->b | TREQ);
                    }
                    s->ifr |= SR_INT;
                    cuda_update_irq(s);
                    cuda_delay_set_sr_int(s);
                }
            }
        }
@@ -411,15 +471,13 @@ static void cuda_update(CUDAState *s)
                s->b = (s->b | TREQ);
            else
                s->b = (s->b & ~TREQ);
            s->ifr |= SR_INT;
            cuda_update_irq(s);
            cuda_delay_set_sr_int(s);
        } else {
            if (!(s->last_b & TIP)) {
                /* handle end of host to cuda transfer */
                packet_received = (s->data_out_index > 0);
                /* always an IRQ at the end of transfer */
                s->ifr |= SR_INT;
                cuda_update_irq(s);
                cuda_delay_set_sr_int(s);
            }
            /* signal if there is data to read */
            if (s->data_in_index < s->data_in_size) {
@@ -456,8 +514,7 @@ static void cuda_send_packet_to_host(CUDAState *s,
    s->data_in_size = len;
    s->data_in_index = 0;
    cuda_update(s);
    s->ifr |= SR_INT;
    cuda_update_irq(s);
    cuda_delay_set_sr_int(s);
}

static void cuda_adb_poll(void *opaque)
@@ -480,7 +537,7 @@ static void cuda_adb_poll(void *opaque)
static void cuda_receive_packet(CUDAState *s,
                                const uint8_t *data, int len)
{
    uint8_t obuf[16];
    uint8_t obuf[16] = { CUDA_PACKET, 0, data[0] };
    int autopoll;
    uint32_t ti;

@@ -497,23 +554,18 @@ static void cuda_receive_packet(CUDAState *s,
                timer_del(s->adb_poll_timer);
            }
        }
        obuf[0] = CUDA_PACKET;
        obuf[1] = data[1];
        cuda_send_packet_to_host(s, obuf, 2);
        cuda_send_packet_to_host(s, obuf, 3);
        break;
    case CUDA_GET_6805_ADDR:
        cuda_send_packet_to_host(s, obuf, 3);
        break;
    case CUDA_SET_TIME:
        ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
        s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec());
        obuf[0] = CUDA_PACKET;
        obuf[1] = 0;
        obuf[2] = 0;
        cuda_send_packet_to_host(s, obuf, 3);
        break;
    case CUDA_GET_TIME:
        ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / get_ticks_per_sec());
        obuf[0] = CUDA_PACKET;
        obuf[1] = 0;
        obuf[2] = 0;
        obuf[3] = ti >> 24;
        obuf[4] = ti >> 16;
        obuf[5] = ti >> 8;
@@ -524,22 +576,34 @@ static void cuda_receive_packet(CUDAState *s,
    case CUDA_SET_DEVICE_LIST:
    case CUDA_SET_AUTO_RATE:
    case CUDA_SET_POWER_MESSAGES:
        obuf[0] = CUDA_PACKET;
        obuf[1] = 0;
        cuda_send_packet_to_host(s, obuf, 2);
        cuda_send_packet_to_host(s, obuf, 3);
        break;
    case CUDA_POWERDOWN:
        obuf[0] = CUDA_PACKET;
        obuf[1] = 0;
        cuda_send_packet_to_host(s, obuf, 2);
        cuda_send_packet_to_host(s, obuf, 3);
        qemu_system_shutdown_request();
        break;
    case CUDA_RESET_SYSTEM:
        obuf[0] = CUDA_PACKET;
        obuf[1] = 0;
        cuda_send_packet_to_host(s, obuf, 2);
        cuda_send_packet_to_host(s, obuf, 3);
        qemu_system_reset_request();
        break;
    case CUDA_COMBINED_FORMAT_IIC:
        obuf[0] = ERROR_PACKET;
        obuf[1] = 0x5;
        obuf[2] = CUDA_PACKET;
        obuf[3] = data[0];
        cuda_send_packet_to_host(s, obuf, 4);
        break;
    case CUDA_GET_SET_IIC:
        if (len == 4) {
            cuda_send_packet_to_host(s, obuf, 3);
        } else {
            obuf[0] = ERROR_PACKET;
            obuf[1] = 0x2;
            obuf[2] = CUDA_PACKET;
            obuf[3] = data[0];
            cuda_send_packet_to_host(s, obuf, 4);
        }
        break;
    default:
        break;
    }
@@ -560,19 +624,21 @@ static void cuda_receive_packet_from_host(CUDAState *s,
    switch(data[0]) {
    case ADB_PACKET:
        {
            uint8_t obuf[ADB_MAX_OUT_LEN + 2];
            uint8_t obuf[ADB_MAX_OUT_LEN + 3];
            int olen;
            olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1);
            if (olen > 0) {
                obuf[0] = ADB_PACKET;
                obuf[1] = 0x00;
                cuda_send_packet_to_host(s, obuf, olen + 2);
            } else {
                /* error */
                obuf[0] = ADB_PACKET;
                obuf[1] = -olen;
                obuf[2] = data[1];
                olen = 0;
                cuda_send_packet_to_host(s, obuf, olen + 3);
            }
            cuda_send_packet_to_host(s, obuf, olen + 2);
        }
        break;
    case CUDA_PACKET:
@@ -671,7 +737,7 @@ static void cuda_reset(DeviceState *dev)

    s->b = 0;
    s->a = 0;
    s->dirb = 0;
    s->dirb = 0xff;
    s->dira = 0;
    s->sr = 0;
    s->acr = 0;
@@ -688,8 +754,9 @@ static void cuda_reset(DeviceState *dev)
    s->timers[0].latch = 0xffff;
    set_counter(s, &s->timers[0], 0xffff);

    s->timers[1].latch = 0;
    set_counter(s, &s->timers[1], 0xffff);
    s->timers[1].latch = 0xffff;

    s->sr_delay_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_set_sr_int, s);
}

static void cuda_realizefn(DeviceState *dev, Error **errp)
@@ -699,7 +766,8 @@ static void cuda_realizefn(DeviceState *dev, Error **errp)

    s->timers[0].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer1, s);
    s->timers[0].frequency = s->frequency;
    s->timers[1].frequency = s->frequency;
    s->timers[1].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cuda_timer2, s);
    s->timers[1].frequency = (SCALE_US * 6000) / 4700;

    qemu_get_timedate(&tm, 0);
    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
+3 −0
Original line number Diff line number Diff line
@@ -103,6 +103,9 @@ typedef struct CUDAState {
    uint8_t last_b;
    uint8_t last_acr;

    /* MacOS 9 is racy and requires a delay upon setting the SR_INT bit */
    QEMUTimer *sr_delay_timer;

    int data_in_size;
    int data_in_index;
    int data_out_index;
+2 −1
Original line number Diff line number Diff line
@@ -371,12 +371,13 @@ static void ppc_core99_init(MachineState *machine)
        /* 970 gets a U3 bus */
        pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
        machine_arch = ARCH_MAC99_U3;
        machine->usb |= defaults_enabled() && !machine->usb_disabled;
    } else {
        pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io());
        machine_arch = ARCH_MAC99;
    }

    machine->usb |= defaults_enabled() && !machine->usb_disabled;

    /* Timebase Frequency */
    if (kvm_enabled()) {
        tbfreq = kvmppc_get_tbfreq();
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ struct MonitorDef {
};

const MonitorDef *target_monitor_defs(void);
int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval);

CPUArchState *mon_get_cpu_env(void);
CPUState *mon_get_cpu(void);
+9 −1
Original line number Diff line number Diff line
@@ -2136,6 +2136,8 @@ static int get_monitor_def(target_long *pval, const char *name)
{
    const MonitorDef *md = target_monitor_defs();
    void *ptr;
    uint64_t tmp = 0;
    int ret;

    if (md == NULL) {
        return -1;
@@ -2163,7 +2165,13 @@ static int get_monitor_def(target_long *pval, const char *name)
            return 0;
        }
    }
    return -1;

    ret = target_get_monitor_def(mon_get_cpu(), name, &tmp);
    if (!ret) {
        *pval = (target_long) tmp;
    }

    return ret;
}

static void next(void)
Loading