From 4248b336d3c1b74e343842c5b478b165d75f5ce8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Nov 2015 22:49:39 +0000 Subject: PPC: Allow Rc bit to be set on mtspr According to the ISA setting the Rc bit on mtspr is undefined behavior. Real 750 hardware simply ignores the bit and doesn't touch cr0 though. Unfortunately, Mac OS 9 relies on this fact and executes a few mtspr instructions (to set XER for example) with Rc set. So let's handle the bit the same way hardware does and ignore it. Signed-off-by: Alexander Graf Signed-off-by: Mark Cave-Ayland Reviewed-by: Thomas Huth Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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), -- cgit v1.2.3 From 488661ee9dd300110a6612d52fe68e2bb3539a5f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Nov 2015 22:49:40 +0000 Subject: PPC: Fix lswx bounds checks The lswx instruction checks whether the desired string actually fits into all defined registers. Unfortunately it does the calculation wrong, resulting in illegal instruction traps for loads that really should fit. Fix it up, making Mac OS happier. Signed-off-by: Alexander Graf Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- target-ppc/mem_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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); -- cgit v1.2.3 From 72f1f97d4927f798167855fda7881b0e22756b20 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Nov 2015 22:49:41 +0000 Subject: PPC: mac99: Always add USB controller The mac99 machines always have a USB controller. Usually not having one around doesn't hurt quite as much, but Mac OS 9 really really wants one or it crashes on bootup. So always add OHCI to make it happy. Signed-off-by: Alexander Graf Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/mac_newworld.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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(); -- cgit v1.2.3 From 6729aa40135bc96d69b5bf5e65a7d463ef7793e7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:42 +0000 Subject: cuda.c: fix CUDA ADB error packet format According to MOL, ADB error packets should be of the form (type, status, cmd) rather than just (type, status). This fixes ADB device detection under MacOS 9. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 0fd75b376f..bfcdcae549 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -560,19 +560,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: -- cgit v1.2.3 From 4202e63c0432c72ba518dd882e99a794620d1665 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:43 +0000 Subject: cuda.c: fix CUDA_PACKET response packet format According to comments in MOL, the response to a CUDA_PACKET should be one of the following: Reply: (CUDA_PACKET, status, cmd) Error: (ERROR_PACKET, status, CUDA_PACKET, cmd) Update cuda_receive_packet() accordingly to reflect this in order to make MacOS 9 happy. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index bfcdcae549..89ec51eebf 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -480,7 +480,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 +497,15 @@ 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_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,20 +516,14 @@ 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; default: -- cgit v1.2.3 From f1f46f74a9de7298977a3ed668e71843fa904c38 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:44 +0000 Subject: cuda.c: implement simple CUDA_GET_6805_ADDR command This simply returns an empty response with no error status as implemented by MOL to allow MacOS 9 boot to proceed further. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 89ec51eebf..1a2ab01c0a 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -499,6 +499,9 @@ static void cuda_receive_packet(CUDAState *s, } 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()); -- cgit v1.2.3 From ce8d3b647b5acc2bec19602d9fac87d3da11ae77 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:45 +0000 Subject: cuda.c: implement dummy IIC access commands These are used by MacOS 9 on boot. Here we return an error except for 4-byte commands which write to the IIC bus in a similar manner to MOL. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 1a2ab01c0a..b7e9deeb15 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -529,6 +529,24 @@ static void cuda_receive_packet(CUDAState *s, 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; } -- cgit v1.2.3 From d271ae36dc1e292ae140f5bbf23e0fc1392dd325 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:46 +0000 Subject: cuda.c: fix CUDA SR interrupt clearing Make sure that we also clear the data and clock interrupts at the same time. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b7e9deeb15..364473fee2 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 */ @@ -261,7 +263,7 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) break; case 10: val = s->sr; - s->ifr &= ~SR_INT; + s->ifr &= ~(SR_INT | SR_CLOCK_INT | SR_DATA_INT); cuda_update_irq(s); break; case 11: -- cgit v1.2.3 From b5ac04103bc3b24042418df1a561096187165fd7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:47 +0000 Subject: cuda.c: add defines for CUDA registers Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 87 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 34 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 364473fee2..c0a3a68025 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -110,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); @@ -226,66 +244,67 @@ 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; 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 | 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); } @@ -300,61 +319,61 @@ 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: + case CUDA_REG_T2CL: s->timers[1].latch = val; set_counter(s, &s->timers[1], val); break; - case 9: + case CUDA_REG_T2CH: set_counter(s, &s->timers[1], (val << 8) | 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; @@ -365,7 +384,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; } -- cgit v1.2.3 From eda14abbb804f8ed2cb903c99ad1852848fa2e42 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:48 +0000 Subject: cuda.c: refactor get_tb() so that the time can be passed in This is in preparation for sharing the code between timers. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index c0a3a68025..e61a3c5967 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -143,10 +143,9 @@ static void cuda_update_irq(CUDAState *s) } } -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) @@ -154,9 +153,10 @@ static unsigned int get_counter(CUDATimer *s) 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; + tb_diff = get_tb(current_time, s->frequency) - s->load_time; d = (tb_diff * 0xBF401675E5DULL) / (s->frequency << 24); if (s->index == 0) { @@ -176,7 +176,8 @@ static unsigned int get_counter(CUDATimer *s) 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); + 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); } -- cgit v1.2.3 From 0174adb611a22bcfeeb123851cf4874e6d922d06 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:49 +0000 Subject: cuda.c: rename get_counter() state variable from s to ti for consistency Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index e61a3c5967..b6da434ee3 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -148,7 +148,7 @@ static uint64_t get_tb(uint64_t time, uint64_t freq) 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; @@ -156,19 +156,19 @@ static unsigned int get_counter(CUDATimer *s) 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(current_time, 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; } -- cgit v1.2.3 From a53cfdcca2834ec7e61fd955c4f24ac233c4ec16 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:50 +0000 Subject: cuda.c: fix T2 timer and enable its interrupt Fix the counter loading logic and enable the T2 interrupt when the timer expires. Otherwise MacOS 9 hangs on boot. Signed-off-by: Mark Cave-Ayland Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index b6da434ee3..9045c3b9f4 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -136,7 +136,7 @@ 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); @@ -175,7 +175,7 @@ static unsigned int get_counter(CUDATimer *ti) static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) { - CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val); + 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; @@ -220,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); @@ -238,6 +238,16 @@ 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 uint32_t cuda_readb(void *opaque, hwaddr addr) { CUDAState *s = opaque; @@ -276,6 +286,7 @@ static uint32_t cuda_readb(void *opaque, hwaddr addr) case CUDA_REG_T2CL: val = get_counter(&s->timers[1]) & 0xff; s->ifr &= ~T2_INT; + cuda_update_irq(s); break; case CUDA_REG_T2CH: val = get_counter(&s->timers[1]) >> 8; @@ -352,11 +363,15 @@ static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val) cuda_timer_update(s, &s->timers[0], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); break; case CUDA_REG_T2CL: - s->timers[1].latch = val; - set_counter(s, &s->timers[1], val); + s->timers[1].latch = (s->timers[1].latch & 0xff00) | val; break; case CUDA_REG_T2CH: - set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); + /* 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 CUDA_REG_SR: s->sr = val; @@ -719,8 +734,7 @@ 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; } static void cuda_realizefn(DeviceState *dev, Error **errp) @@ -730,7 +744,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; -- cgit v1.2.3 From cffc331a3156870d54883bc79e4278472ffd8f1d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Wed, 11 Nov 2015 22:49:51 +0000 Subject: cuda.c: add delay to setting of SR_INT bit MacOS 9 is racy when it comes to accessing the shift register. Fix this by introducing a small delay between data accesses and raising the SR_INT interrupt bit. Signed-off-by: Mark Cave-Ayland Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/misc/macio/cuda.c | 44 +++++++++++++++++++++++++++++++++----------- hw/ppc/mac.h | 3 +++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 9045c3b9f4..9db4c64150 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -248,6 +248,31 @@ static void cuda_timer2(void *opaque) 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; @@ -421,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 { @@ -435,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); } } } @@ -448,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) { @@ -493,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) @@ -717,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; @@ -735,6 +755,8 @@ static void cuda_reset(DeviceState *dev) set_counter(s, &s->timers[0], 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) 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; -- cgit v1.2.3 From 0a9516c2d6711cb6760a726952bdbbe931fd045c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 12 Nov 2015 14:44:23 +1100 Subject: monitor/target-ppc: Define target_get_monitor_def At the moment get_monitor_def() returns only registers from statically defined monitor_defs array. However there is a lot of BOOK3S SPRs which are not in the list and cannot be printed from the monitor. This adds a new target platform hook - target_get_monitor_def(). The hook is called if a register was not found in the static array returned by the target_monitor_defs() hook. The hook is only defined for POWERPC, it returns registered SPRs and fails on unregistered ones providing the user with information on what is actually supported on the running CPU. The register value is saved as uint64_t as it is the biggest supported register size; target_ulong cannot be used because of the stub - it is in a "common" code and cannot include "cpu.h", etc; this is also why the hook prototype is redefined in the stub instead of being included from some header. This replaces static descriptors for GPRs, FPRs, SRs with a helper which looks for a value in a corresponding array in the CPUPPCState. The immediate effect is that all 32 SRs can be printed now (instead of 16); later this can be reused for VSX or TM registers. This replaces callbacks for MSR and XER with static descriptors in monitor_defs as they are stored in CPUPPCState. While we are here, this adds "cr" as a synonym of "ccr". Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- include/monitor/hmp-target.h | 1 + monitor.c | 10 +- stubs/Makefile.objs | 1 + stubs/target-get-monitor-def.c | 31 ++++++ target-ppc/cpu-qom.h | 2 + target-ppc/monitor.c | 235 +++++++++++------------------------------ 6 files changed, 107 insertions(+), 173 deletions(-) create mode 100644 stubs/target-get-monitor-def.c 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); diff --git a/monitor.c b/monitor.c index 32958407dd..e4cf34e3cb 100644 --- a/monitor.c +++ b/monitor.c @@ -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 + * + * 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 . + */ + +#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/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; +} -- cgit v1.2.3