diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-11-12 13:41:44 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-11-12 13:41:44 +0000 |
commit | df1ac44e9f0c1b1d775c65b6e86fbcac0be77930 (patch) | |
tree | e95e0da6ac98169a2b7df2722ea5bef207f9ebcb | |
parent | fd717e789010012c5f0537269df19ef19d469baf (diff) | |
parent | 0a9516c2d6711cb6760a726952bdbbe931fd045c (diff) | |
download | qemu-df1ac44e9f0c1b1d775c65b6e86fbcac0be77930.zip |
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: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/misc/macio/cuda.c | 246 | ||||
-rw-r--r-- | hw/ppc/mac.h | 3 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 3 | ||||
-rw-r--r-- | include/monitor/hmp-target.h | 1 | ||||
-rw-r--r-- | monitor.c | 10 | ||||
-rw-r--r-- | stubs/Makefile.objs | 1 | ||||
-rw-r--r-- | stubs/target-get-monitor-def.c | 31 | ||||
-rw-r--r-- | target-ppc/cpu-qom.h | 2 | ||||
-rw-r--r-- | target-ppc/mem_helper.c | 5 | ||||
-rw-r--r-- | target-ppc/monitor.c | 235 | ||||
-rw-r--r-- | target-ppc/translate.c | 2 |
11 files changed, 273 insertions, 266 deletions
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 0fd75b376f..9db4c64150 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -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; diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 8bdba30c1e..e375ed2b2b 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -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; diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 66d016c6fa..1b9a573cae 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -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(); diff --git a/include/monitor/hmp-target.h b/include/monitor/hmp-target.h index 213566c612..bc2c9c04d0 100644 --- a/include/monitor/hmp-target.h +++ b/include/monitor/hmp-target.h @@ -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); @@ -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) diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 330e1a48f0..d7898a0c4a 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -36,4 +36,5 @@ stub-obj-y += cpus.o stub-obj-y += kvm.o stub-obj-y += qmp_pc_dimm_device_list.o stub-obj-y += target-monitor-defs.o +stub-obj-y += target-get-monitor-def.o stub-obj-y += vhost.o diff --git a/stubs/target-get-monitor-def.c b/stubs/target-get-monitor-def.c new file mode 100644 index 0000000000..711a9ae46b --- /dev/null +++ b/stubs/target-get-monitor-def.c @@ -0,0 +1,31 @@ +/* + * Stub for target_get_monitor_def. + * + * Copyright IBM Corp., 2015 + * + * Author: Alexey Kardashevskiy <aik@ozlabs.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "stdint.h" + +typedef struct CPUState CPUState; + +int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval); + +int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval) +{ + return -1; +} diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index 6967a8028b..bc20504b3d 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -118,6 +118,8 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, int flags); +int ppc_cpu_get_monitor_def(CPUState *cs, const char *name, + uint64_t *pval); hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 6d37dae7b0..7e1f234aa5 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -100,8 +100,9 @@ void helper_lswx(CPUPPCState *env, target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) { if (likely(xer_bc != 0)) { - if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) || - (reg < rb && (reg + xer_bc) > rb))) { + int num_used_regs = (xer_bc + 3) / 4; + if (unlikely((ra != 0 && reg < ra && (reg + num_used_regs) > ra) || + (reg < rb && (reg + num_used_regs) > rb))) { helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX); diff --git a/target-ppc/monitor.c b/target-ppc/monitor.c index 9cb1fe97c9..bc571b87ae 100644 --- a/target-ppc/monitor.c +++ b/target-ppc/monitor.c @@ -39,18 +39,6 @@ static target_long monitor_get_ccr (const struct MonitorDef *md, int val) return u; } -static target_long monitor_get_msr (const struct MonitorDef *md, int val) -{ - CPUArchState *env = mon_get_cpu_env(); - return env->msr; -} - -static target_long monitor_get_xer (const struct MonitorDef *md, int val) -{ - CPUArchState *env = mon_get_cpu_env(); - return env->xer; -} - static target_long monitor_get_decr (const struct MonitorDef *md, int val) { CPUArchState *env = mon_get_cpu_env(); @@ -76,176 +64,19 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict) dump_mmu((FILE*)mon, (fprintf_function)monitor_printf, env1); } - const MonitorDef monitor_defs[] = { - /* General purpose registers */ - { "r0", offsetof(CPUPPCState, gpr[0]) }, - { "r1", offsetof(CPUPPCState, gpr[1]) }, - { "r2", offsetof(CPUPPCState, gpr[2]) }, - { "r3", offsetof(CPUPPCState, gpr[3]) }, - { "r4", offsetof(CPUPPCState, gpr[4]) }, - { "r5", offsetof(CPUPPCState, gpr[5]) }, - { "r6", offsetof(CPUPPCState, gpr[6]) }, - { "r7", offsetof(CPUPPCState, gpr[7]) }, - { "r8", offsetof(CPUPPCState, gpr[8]) }, - { "r9", offsetof(CPUPPCState, gpr[9]) }, - { "r10", offsetof(CPUPPCState, gpr[10]) }, - { "r11", offsetof(CPUPPCState, gpr[11]) }, - { "r12", offsetof(CPUPPCState, gpr[12]) }, - { "r13", offsetof(CPUPPCState, gpr[13]) }, - { "r14", offsetof(CPUPPCState, gpr[14]) }, - { "r15", offsetof(CPUPPCState, gpr[15]) }, - { "r16", offsetof(CPUPPCState, gpr[16]) }, - { "r17", offsetof(CPUPPCState, gpr[17]) }, - { "r18", offsetof(CPUPPCState, gpr[18]) }, - { "r19", offsetof(CPUPPCState, gpr[19]) }, - { "r20", offsetof(CPUPPCState, gpr[20]) }, - { "r21", offsetof(CPUPPCState, gpr[21]) }, - { "r22", offsetof(CPUPPCState, gpr[22]) }, - { "r23", offsetof(CPUPPCState, gpr[23]) }, - { "r24", offsetof(CPUPPCState, gpr[24]) }, - { "r25", offsetof(CPUPPCState, gpr[25]) }, - { "r26", offsetof(CPUPPCState, gpr[26]) }, - { "r27", offsetof(CPUPPCState, gpr[27]) }, - { "r28", offsetof(CPUPPCState, gpr[28]) }, - { "r29", offsetof(CPUPPCState, gpr[29]) }, - { "r30", offsetof(CPUPPCState, gpr[30]) }, - { "r31", offsetof(CPUPPCState, gpr[31]) }, - /* Floating point registers */ - { "f0", offsetof(CPUPPCState, fpr[0]) }, - { "f1", offsetof(CPUPPCState, fpr[1]) }, - { "f2", offsetof(CPUPPCState, fpr[2]) }, - { "f3", offsetof(CPUPPCState, fpr[3]) }, - { "f4", offsetof(CPUPPCState, fpr[4]) }, - { "f5", offsetof(CPUPPCState, fpr[5]) }, - { "f6", offsetof(CPUPPCState, fpr[6]) }, - { "f7", offsetof(CPUPPCState, fpr[7]) }, - { "f8", offsetof(CPUPPCState, fpr[8]) }, - { "f9", offsetof(CPUPPCState, fpr[9]) }, - { "f10", offsetof(CPUPPCState, fpr[10]) }, - { "f11", offsetof(CPUPPCState, fpr[11]) }, - { "f12", offsetof(CPUPPCState, fpr[12]) }, - { "f13", offsetof(CPUPPCState, fpr[13]) }, - { "f14", offsetof(CPUPPCState, fpr[14]) }, - { "f15", offsetof(CPUPPCState, fpr[15]) }, - { "f16", offsetof(CPUPPCState, fpr[16]) }, - { "f17", offsetof(CPUPPCState, fpr[17]) }, - { "f18", offsetof(CPUPPCState, fpr[18]) }, - { "f19", offsetof(CPUPPCState, fpr[19]) }, - { "f20", offsetof(CPUPPCState, fpr[20]) }, - { "f21", offsetof(CPUPPCState, fpr[21]) }, - { "f22", offsetof(CPUPPCState, fpr[22]) }, - { "f23", offsetof(CPUPPCState, fpr[23]) }, - { "f24", offsetof(CPUPPCState, fpr[24]) }, - { "f25", offsetof(CPUPPCState, fpr[25]) }, - { "f26", offsetof(CPUPPCState, fpr[26]) }, - { "f27", offsetof(CPUPPCState, fpr[27]) }, - { "f28", offsetof(CPUPPCState, fpr[28]) }, - { "f29", offsetof(CPUPPCState, fpr[29]) }, - { "f30", offsetof(CPUPPCState, fpr[30]) }, - { "f31", offsetof(CPUPPCState, fpr[31]) }, { "fpscr", offsetof(CPUPPCState, fpscr) }, /* Next instruction pointer */ { "nip|pc", offsetof(CPUPPCState, nip) }, { "lr", offsetof(CPUPPCState, lr) }, { "ctr", offsetof(CPUPPCState, ctr) }, { "decr", 0, &monitor_get_decr, }, - { "ccr", 0, &monitor_get_ccr, }, + { "ccr|cr", 0, &monitor_get_ccr, }, /* Machine state register */ - { "msr", 0, &monitor_get_msr, }, - { "xer", 0, &monitor_get_xer, }, + { "xer", offsetof(CPUPPCState, xer) }, + { "msr", offsetof(CPUPPCState, msr) }, { "tbu", 0, &monitor_get_tbu, }, { "tbl", 0, &monitor_get_tbl, }, - /* Segment registers */ - { "sdr1", offsetof(CPUPPCState, spr[SPR_SDR1]) }, - { "sr0", offsetof(CPUPPCState, sr[0]) }, - { "sr1", offsetof(CPUPPCState, sr[1]) }, - { "sr2", offsetof(CPUPPCState, sr[2]) }, - { "sr3", offsetof(CPUPPCState, sr[3]) }, - { "sr4", offsetof(CPUPPCState, sr[4]) }, - { "sr5", offsetof(CPUPPCState, sr[5]) }, - { "sr6", offsetof(CPUPPCState, sr[6]) }, - { "sr7", offsetof(CPUPPCState, sr[7]) }, - { "sr8", offsetof(CPUPPCState, sr[8]) }, - { "sr9", offsetof(CPUPPCState, sr[9]) }, - { "sr10", offsetof(CPUPPCState, sr[10]) }, - { "sr11", offsetof(CPUPPCState, sr[11]) }, - { "sr12", offsetof(CPUPPCState, sr[12]) }, - { "sr13", offsetof(CPUPPCState, sr[13]) }, - { "sr14", offsetof(CPUPPCState, sr[14]) }, - { "sr15", offsetof(CPUPPCState, sr[15]) }, - /* Too lazy to put BATs... */ - { "pvr", offsetof(CPUPPCState, spr[SPR_PVR]) }, - - { "srr0", offsetof(CPUPPCState, spr[SPR_SRR0]) }, - { "srr1", offsetof(CPUPPCState, spr[SPR_SRR1]) }, - { "dar", offsetof(CPUPPCState, spr[SPR_DAR]) }, - { "dsisr", offsetof(CPUPPCState, spr[SPR_DSISR]) }, - { "cfar", offsetof(CPUPPCState, spr[SPR_CFAR]) }, - { "sprg0", offsetof(CPUPPCState, spr[SPR_SPRG0]) }, - { "sprg1", offsetof(CPUPPCState, spr[SPR_SPRG1]) }, - { "sprg2", offsetof(CPUPPCState, spr[SPR_SPRG2]) }, - { "sprg3", offsetof(CPUPPCState, spr[SPR_SPRG3]) }, - { "sprg4", offsetof(CPUPPCState, spr[SPR_SPRG4]) }, - { "sprg5", offsetof(CPUPPCState, spr[SPR_SPRG5]) }, - { "sprg6", offsetof(CPUPPCState, spr[SPR_SPRG6]) }, - { "sprg7", offsetof(CPUPPCState, spr[SPR_SPRG7]) }, - { "pid", offsetof(CPUPPCState, spr[SPR_BOOKE_PID]) }, - { "csrr0", offsetof(CPUPPCState, spr[SPR_BOOKE_CSRR0]) }, - { "csrr1", offsetof(CPUPPCState, spr[SPR_BOOKE_CSRR1]) }, - { "esr", offsetof(CPUPPCState, spr[SPR_BOOKE_ESR]) }, - { "dear", offsetof(CPUPPCState, spr[SPR_BOOKE_DEAR]) }, - { "mcsr", offsetof(CPUPPCState, spr[SPR_BOOKE_MCSR]) }, - { "tsr", offsetof(CPUPPCState, spr[SPR_BOOKE_TSR]) }, - { "tcr", offsetof(CPUPPCState, spr[SPR_BOOKE_TCR]) }, - { "vrsave", offsetof(CPUPPCState, spr[SPR_VRSAVE]) }, - { "pir", offsetof(CPUPPCState, spr[SPR_BOOKE_PIR]) }, - { "mcsrr0", offsetof(CPUPPCState, spr[SPR_BOOKE_MCSRR0]) }, - { "mcsrr1", offsetof(CPUPPCState, spr[SPR_BOOKE_MCSRR1]) }, - { "decar", offsetof(CPUPPCState, spr[SPR_BOOKE_DECAR]) }, - { "ivpr", offsetof(CPUPPCState, spr[SPR_BOOKE_IVPR]) }, - { "epcr", offsetof(CPUPPCState, spr[SPR_BOOKE_EPCR]) }, - { "sprg8", offsetof(CPUPPCState, spr[SPR_BOOKE_SPRG8]) }, - { "ivor0", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR0]) }, - { "ivor1", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR1]) }, - { "ivor2", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR2]) }, - { "ivor3", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR3]) }, - { "ivor4", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR4]) }, - { "ivor5", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR5]) }, - { "ivor6", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR6]) }, - { "ivor7", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR7]) }, - { "ivor8", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR8]) }, - { "ivor9", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR9]) }, - { "ivor10", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR10]) }, - { "ivor11", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR11]) }, - { "ivor12", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR12]) }, - { "ivor13", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR13]) }, - { "ivor14", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR14]) }, - { "ivor15", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR15]) }, - { "ivor32", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR32]) }, - { "ivor33", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR33]) }, - { "ivor34", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR34]) }, - { "ivor35", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR35]) }, - { "ivor36", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR36]) }, - { "ivor37", offsetof(CPUPPCState, spr[SPR_BOOKE_IVOR37]) }, - { "mas0", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS0]) }, - { "mas1", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS1]) }, - { "mas2", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS2]) }, - { "mas3", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS3]) }, - { "mas4", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS4]) }, - { "mas6", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS6]) }, - { "mas7", offsetof(CPUPPCState, spr[SPR_BOOKE_MAS7]) }, - { "mmucfg", offsetof(CPUPPCState, spr[SPR_MMUCFG]) }, - { "tlb0cfg", offsetof(CPUPPCState, spr[SPR_BOOKE_TLB0CFG]) }, - { "tlb1cfg", offsetof(CPUPPCState, spr[SPR_BOOKE_TLB1CFG]) }, - { "epr", offsetof(CPUPPCState, spr[SPR_BOOKE_EPR]) }, - { "eplc", offsetof(CPUPPCState, spr[SPR_BOOKE_EPLC]) }, - { "epsc", offsetof(CPUPPCState, spr[SPR_BOOKE_EPSC]) }, - { "svr", offsetof(CPUPPCState, spr[SPR_E500_SVR]) }, - { "mcar", offsetof(CPUPPCState, spr[SPR_Exxx_MCAR]) }, - { "pid1", offsetof(CPUPPCState, spr[SPR_BOOKE_PID1]) }, - { "pid2", offsetof(CPUPPCState, spr[SPR_BOOKE_PID2]) }, - { "hid0", offsetof(CPUPPCState, spr[SPR_HID0]) }, { NULL }, }; @@ -253,3 +84,63 @@ const MonitorDef *target_monitor_defs(void) { return monitor_defs; } + +static int ppc_cpu_get_reg_num(const char *numstr, int maxnum, int *pregnum) +{ + int regnum; + char *endptr = NULL; + + if (!*numstr) { + return false; + } + + regnum = strtoul(numstr, &endptr, 10); + if (*endptr || (regnum >= maxnum)) { + return false; + } + *pregnum = regnum; + + return true; +} + +int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval) +{ + int i, regnum; + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + /* General purpose registers */ + if ((tolower(name[0]) == 'r') && + ppc_cpu_get_reg_num(name + 1, ARRAY_SIZE(env->gpr), ®num)) { + *pval = env->gpr[regnum]; + return 0; + } + + /* Floating point registers */ + if ((tolower(name[0]) == 'f') && + ppc_cpu_get_reg_num(name + 1, ARRAY_SIZE(env->fpr), ®num)) { + *pval = env->fpr[regnum]; + return 0; + } + + /* Special purpose registers */ + for (i = 0; i < ARRAY_SIZE(env->spr_cb); ++i) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (spr->name && (strcasecmp(name, spr->name) == 0)) { + *pval = env->spr[i]; + return 0; + } + } + + /* Segment registers */ +#if !defined(CONFIG_USER_ONLY) + if ((strncasecmp(name, "sr", 2) == 0) && + ppc_cpu_get_reg_num(name + 2, ARRAY_SIZE(env->sr), ®num)) { + *pval = env->sr[regnum]; + return 0; + } +#endif + + return -EINVAL; +} diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 308ad68880..41a7258486 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9884,7 +9884,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC), GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B), #endif GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC), -GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC), +GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC), GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE), GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE), |