2 * QEMU Sun4u/Sun4v System Emulator common routines
4 * Copyright (c) 2005 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "qemu/osdep.h"
28 #include "hw/boards.h"
29 #include "hw/char/serial.h"
30 #include "hw/sparc/sparc64.h"
31 #include "qemu/timer.h"
32 #include "sysemu/reset.h"
36 #define TICK_MAX 0x7fffffffffffffffULL
38 void cpu_check_irqs(CPUSPARCState
*env
)
41 uint32_t pil
= env
->pil_in
|
42 (env
->softint
& ~(SOFTINT_TIMER
| SOFTINT_STIMER
));
44 /* We should be holding the BQL before we mess with IRQs */
45 g_assert(qemu_mutex_iothread_locked());
47 /* TT_IVEC has a higher priority (16) than TT_EXTINT (31..17) */
48 if (env
->ivec_status
& 0x20) {
52 /* check if TM or SM in SOFTINT are set
53 setting these also causes interrupt 14 */
54 if (env
->softint
& (SOFTINT_TIMER
| SOFTINT_STIMER
)) {
58 /* The bit corresponding to psrpil is (1<< psrpil), the next bit
60 if (pil
< (2 << env
->psrpil
)) {
61 if (cs
->interrupt_request
& CPU_INTERRUPT_HARD
) {
62 trace_sparc64_cpu_check_irqs_reset_irq(env
->interrupt_index
);
63 env
->interrupt_index
= 0;
64 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
69 if (cpu_interrupts_enabled(env
)) {
73 for (i
= 15; i
> env
->psrpil
; i
--) {
75 int old_interrupt
= env
->interrupt_index
;
76 int new_interrupt
= TT_EXTINT
| i
;
78 if (unlikely(env
->tl
> 0 && cpu_tsptr(env
)->tt
> new_interrupt
79 && ((cpu_tsptr(env
)->tt
& 0x1f0) == TT_EXTINT
))) {
80 trace_sparc64_cpu_check_irqs_noset_irq(env
->tl
,
83 } else if (old_interrupt
!= new_interrupt
) {
84 env
->interrupt_index
= new_interrupt
;
85 trace_sparc64_cpu_check_irqs_set_irq(i
, old_interrupt
,
87 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
92 } else if (cs
->interrupt_request
& CPU_INTERRUPT_HARD
) {
93 trace_sparc64_cpu_check_irqs_disabled(pil
, env
->pil_in
, env
->softint
,
94 env
->interrupt_index
);
95 env
->interrupt_index
= 0;
96 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
100 static void cpu_kick_irq(SPARCCPU
*cpu
)
102 CPUState
*cs
= CPU(cpu
);
103 CPUSPARCState
*env
= &cpu
->env
;
110 void sparc64_cpu_set_ivec_irq(void *opaque
, int irq
, int level
)
112 SPARCCPU
*cpu
= opaque
;
113 CPUSPARCState
*env
= &cpu
->env
;
117 if (!(env
->ivec_status
& 0x20)) {
118 trace_sparc64_cpu_ivec_raise_irq(irq
);
121 env
->interrupt_index
= TT_IVEC
;
122 env
->ivec_status
|= 0x20;
123 env
->ivec_data
[0] = (0x1f << 6) | irq
;
124 env
->ivec_data
[1] = 0;
125 env
->ivec_data
[2] = 0;
126 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
129 if (env
->ivec_status
& 0x20) {
130 trace_sparc64_cpu_ivec_lower_irq(irq
);
132 env
->ivec_status
&= ~0x20;
133 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
138 typedef struct ResetData
{
143 static CPUTimer
*cpu_timer_create(const char *name
, SPARCCPU
*cpu
,
144 QEMUBHFunc
*cb
, uint32_t frequency
,
145 uint64_t disabled_mask
, uint64_t npt_mask
)
147 CPUTimer
*timer
= g_malloc0(sizeof(CPUTimer
));
150 timer
->frequency
= frequency
;
151 timer
->disabled_mask
= disabled_mask
;
152 timer
->npt_mask
= npt_mask
;
156 timer
->clock_offset
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
158 timer
->qtimer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, cb
, cpu
);
163 static void cpu_timer_reset(CPUTimer
*timer
)
166 timer
->clock_offset
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
168 timer_del(timer
->qtimer
);
171 static void main_cpu_reset(void *opaque
)
173 ResetData
*s
= (ResetData
*)opaque
;
174 CPUSPARCState
*env
= &s
->cpu
->env
;
175 static unsigned int nr_resets
;
177 cpu_reset(CPU(s
->cpu
));
179 cpu_timer_reset(env
->tick
);
180 cpu_timer_reset(env
->stick
);
181 cpu_timer_reset(env
->hstick
);
183 env
->gregs
[1] = 0; /* Memory start */
184 env
->gregs
[2] = current_machine
->ram_size
; /* Memory size */
185 env
->gregs
[3] = 0; /* Machine description XXX */
186 if (nr_resets
++ == 0) {
188 env
->pc
= s
->prom_addr
+ 0x20ULL
;
190 env
->pc
= s
->prom_addr
+ 0x40ULL
;
192 env
->npc
= env
->pc
+ 4;
195 static void tick_irq(void *opaque
)
197 SPARCCPU
*cpu
= opaque
;
198 CPUSPARCState
*env
= &cpu
->env
;
200 CPUTimer
*timer
= env
->tick
;
202 if (timer
->disabled
) {
203 trace_sparc64_cpu_tick_irq_disabled();
206 trace_sparc64_cpu_tick_irq_fire();
209 env
->softint
|= SOFTINT_TIMER
;
213 static void stick_irq(void *opaque
)
215 SPARCCPU
*cpu
= opaque
;
216 CPUSPARCState
*env
= &cpu
->env
;
218 CPUTimer
*timer
= env
->stick
;
220 if (timer
->disabled
) {
221 trace_sparc64_cpu_stick_irq_disabled();
224 trace_sparc64_cpu_stick_irq_fire();
227 env
->softint
|= SOFTINT_STIMER
;
231 static void hstick_irq(void *opaque
)
233 SPARCCPU
*cpu
= opaque
;
234 CPUSPARCState
*env
= &cpu
->env
;
236 CPUTimer
*timer
= env
->hstick
;
238 if (timer
->disabled
) {
239 trace_sparc64_cpu_hstick_irq_disabled();
242 trace_sparc64_cpu_hstick_irq_fire();
245 env
->softint
|= SOFTINT_STIMER
;
249 static int64_t cpu_to_timer_ticks(int64_t cpu_ticks
, uint32_t frequency
)
251 return muldiv64(cpu_ticks
, NANOSECONDS_PER_SECOND
, frequency
);
254 static uint64_t timer_to_cpu_ticks(int64_t timer_ticks
, uint32_t frequency
)
256 return muldiv64(timer_ticks
, frequency
, NANOSECONDS_PER_SECOND
);
259 void cpu_tick_set_count(CPUTimer
*timer
, uint64_t count
)
261 uint64_t real_count
= count
& ~timer
->npt_mask
;
262 uint64_t npt_bit
= count
& timer
->npt_mask
;
264 int64_t vm_clock_offset
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) -
265 cpu_to_timer_ticks(real_count
, timer
->frequency
);
267 trace_sparc64_cpu_tick_set_count(timer
->name
, real_count
,
268 timer
->npt
? "disabled" : "enabled",
271 timer
->npt
= npt_bit
? 1 : 0;
272 timer
->clock_offset
= vm_clock_offset
;
275 uint64_t cpu_tick_get_count(CPUTimer
*timer
)
277 uint64_t real_count
= timer_to_cpu_ticks(
278 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - timer
->clock_offset
,
281 trace_sparc64_cpu_tick_get_count(timer
->name
, real_count
,
282 timer
->npt
? "disabled" : "enabled",
286 real_count
|= timer
->npt_mask
;
292 void cpu_tick_set_limit(CPUTimer
*timer
, uint64_t limit
)
294 int64_t now
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
296 uint64_t real_limit
= limit
& ~timer
->disabled_mask
;
297 timer
->disabled
= (limit
& timer
->disabled_mask
) ? 1 : 0;
299 int64_t expires
= cpu_to_timer_ticks(real_limit
, timer
->frequency
) +
306 trace_sparc64_cpu_tick_set_limit(timer
->name
, real_limit
,
307 timer
->disabled
? "disabled" : "enabled",
310 now
- timer
->clock_offset
,
314 expires
- now
, timer
->frequency
318 trace_sparc64_cpu_tick_set_limit_zero(timer
->name
);
319 timer_del(timer
->qtimer
);
320 } else if (timer
->disabled
) {
321 timer_del(timer
->qtimer
);
323 timer_mod(timer
->qtimer
, expires
);
327 SPARCCPU
*sparc64_cpu_devinit(const char *cpu_type
, uint64_t prom_addr
)
331 ResetData
*reset_info
;
333 uint32_t tick_frequency
= 100 * 1000000;
334 uint32_t stick_frequency
= 100 * 1000000;
335 uint32_t hstick_frequency
= 100 * 1000000;
337 cpu
= SPARC_CPU(cpu_create(cpu_type
));
338 qdev_init_gpio_in_named(DEVICE(cpu
), sparc64_cpu_set_ivec_irq
,
339 "ivec-irq", IVEC_MAX
);
342 env
->tick
= cpu_timer_create("tick", cpu
, tick_irq
,
343 tick_frequency
, TICK_INT_DIS
,
346 env
->stick
= cpu_timer_create("stick", cpu
, stick_irq
,
347 stick_frequency
, TICK_INT_DIS
,
350 env
->hstick
= cpu_timer_create("hstick", cpu
, hstick_irq
,
351 hstick_frequency
, TICK_INT_DIS
,
354 reset_info
= g_malloc0(sizeof(ResetData
));
355 reset_info
->cpu
= cpu
;
356 reset_info
->prom_addr
= prom_addr
;
357 qemu_register_reset(main_cpu_reset
, reset_info
);