increase max kernel size with initrd
[qemu] / hw / slavio_intctl.c
1 /*
2  * QEMU Sparc SLAVIO interrupt controller emulation
3  * 
4  * Copyright (c) 2003-2005 Fabrice Bellard
5  * 
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25 //#define DEBUG_IRQ_COUNT
26 //#define DEBUG_IRQ
27
28 #ifdef DEBUG_IRQ
29 #define DPRINTF(fmt, args...) \
30 do { printf("IRQ: " fmt , ##args); } while (0)
31 #else
32 #define DPRINTF(fmt, args...)
33 #endif
34
35 /*
36  * Registers of interrupt controller in sun4m.
37  *
38  * This is the interrupt controller part of chip STP2001 (Slave I/O), also
39  * produced as NCR89C105. See
40  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
41  *
42  * There is a system master controller and one for each cpu.
43  * 
44  */
45
46 #define MAX_CPUS 16
47
48 typedef struct SLAVIO_INTCTLState {
49     uint32_t intreg_pending[MAX_CPUS];
50     uint32_t intregm_pending;
51     uint32_t intregm_disabled;
52     uint32_t target_cpu;
53 #ifdef DEBUG_IRQ_COUNT
54     uint64_t irq_count[32];
55 #endif
56     CPUState *cpu_envs[MAX_CPUS];
57 } SLAVIO_INTCTLState;
58
59 #define INTCTL_MAXADDR 0xf
60 #define INTCTLM_MAXADDR 0xf
61 static void slavio_check_interrupts(void *opaque);
62
63 // per-cpu interrupt controller
64 static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
65 {
66     SLAVIO_INTCTLState *s = opaque;
67     uint32_t saddr;
68     int cpu;
69
70     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
71     saddr = (addr & INTCTL_MAXADDR) >> 2;
72     switch (saddr) {
73     case 0:
74         return s->intreg_pending[cpu];
75     default:
76         break;
77     }
78     return 0;
79 }
80
81 static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
82 {
83     SLAVIO_INTCTLState *s = opaque;
84     uint32_t saddr;
85     int cpu;
86
87     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
88     saddr = (addr & INTCTL_MAXADDR) >> 2;
89     switch (saddr) {
90     case 1: // clear pending softints
91         if (val & 0x4000)
92             val |= 80000000;
93         val &= 0xfffe0000;
94         s->intreg_pending[cpu] &= ~val;
95         DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
96         break;
97     case 2: // set softint
98         val &= 0xfffe0000;
99         s->intreg_pending[cpu] |= val;
100         slavio_check_interrupts(s);
101         DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
102         break;
103     default:
104         break;
105     }
106 }
107
108 static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
109     slavio_intctl_mem_readl,
110     slavio_intctl_mem_readl,
111     slavio_intctl_mem_readl,
112 };
113
114 static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
115     slavio_intctl_mem_writel,
116     slavio_intctl_mem_writel,
117     slavio_intctl_mem_writel,
118 };
119
120 // master system interrupt controller
121 static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
122 {
123     SLAVIO_INTCTLState *s = opaque;
124     uint32_t saddr;
125
126     saddr = (addr & INTCTLM_MAXADDR) >> 2;
127     switch (saddr) {
128     case 0:
129         return s->intregm_pending & 0x7fffffff;
130     case 1:
131         return s->intregm_disabled;
132     case 4:
133         return s->target_cpu;
134     default:
135         break;
136     }
137     return 0;
138 }
139
140 static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
141 {
142     SLAVIO_INTCTLState *s = opaque;
143     uint32_t saddr;
144
145     saddr = (addr & INTCTLM_MAXADDR) >> 2;
146     switch (saddr) {
147     case 2: // clear (enable)
148         // Force clear unused bits
149         val &= ~0x4fb2007f;
150         s->intregm_disabled &= ~val;
151         DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
152         slavio_check_interrupts(s);
153         break;
154     case 3: // set (disable, clear pending)
155         // Force clear unused bits
156         val &= ~0x4fb2007f;
157         s->intregm_disabled |= val;
158         s->intregm_pending &= ~val;
159         DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
160         break;
161     case 4:
162         s->target_cpu = val & (MAX_CPUS - 1);
163         DPRINTF("Set master irq cpu %d\n", s->target_cpu);
164         break;
165     default:
166         break;
167     }
168 }
169
170 static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
171     slavio_intctlm_mem_readl,
172     slavio_intctlm_mem_readl,
173     slavio_intctlm_mem_readl,
174 };
175
176 static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
177     slavio_intctlm_mem_writel,
178     slavio_intctlm_mem_writel,
179     slavio_intctlm_mem_writel,
180 };
181
182 void slavio_pic_info(void *opaque)
183 {
184     SLAVIO_INTCTLState *s = opaque;
185     int i;
186
187     for (i = 0; i < MAX_CPUS; i++) {
188         term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
189     }
190     term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
191 }
192
193 void slavio_irq_info(void *opaque)
194 {
195 #ifndef DEBUG_IRQ_COUNT
196     term_printf("irq statistic code not compiled.\n");
197 #else
198     SLAVIO_INTCTLState *s = opaque;
199     int i;
200     int64_t count;
201
202     term_printf("IRQ statistics:\n");
203     for (i = 0; i < 32; i++) {
204         count = s->irq_count[i];
205         if (count > 0)
206             term_printf("%2d: %lld\n", i, count);
207     }
208 #endif
209 }
210
211 static const uint32_t intbit_to_level[32] = {
212     2, 3, 5, 7, 9, 11, 0, 14,   3, 5, 7, 9, 11, 13, 12, 12,
213     6, 0, 4, 10, 8, 0, 11, 0,   0, 0, 0, 0, 15, 0, 15, 0,
214 };
215
216 static void slavio_check_interrupts(void *opaque)
217 {
218     CPUState *env;
219     SLAVIO_INTCTLState *s = opaque;
220     uint32_t pending = s->intregm_pending;
221     unsigned int i, j, max = 0;
222
223     pending &= ~s->intregm_disabled;
224
225     if (pending && !(s->intregm_disabled & 0x80000000)) {
226         for (i = 0; i < 32; i++) {
227             if (pending & (1 << i)) {
228                 if (max < intbit_to_level[i])
229                     max = intbit_to_level[i];
230             }
231         }
232         env = s->cpu_envs[s->target_cpu];
233         if (!env) {
234             DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
235         }
236         else {
237             if (env->halted)
238                 env->halted = 0;
239             if (env->interrupt_index == 0) {
240                 DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
241 #ifdef DEBUG_IRQ_COUNT
242                 s->irq_count[max]++;
243 #endif
244                 env->interrupt_index = TT_EXTINT | max;
245                 cpu_interrupt(env, CPU_INTERRUPT_HARD);
246             }
247             else
248                 DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
249         }
250     }
251     else
252         DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
253     
254     for (i = 0; i < MAX_CPUS; i++) {
255         max = 0;
256         env = s->cpu_envs[i];
257         if (!env)
258             continue;
259         for (j = 17; j < 32; j++) {
260             if (s->intreg_pending[i] & (1 << j)) {
261                 if (max < j - 16)
262                     max = j - 16;
263             }
264         }
265         if (max > 0) {
266             if (env->halted)
267                 env->halted = 0;
268             if (env->interrupt_index == 0) {
269                 DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
270 #ifdef DEBUG_IRQ_COUNT
271                 s->irq_count[max]++;
272 #endif
273                 env->interrupt_index = TT_EXTINT | max;
274                 cpu_interrupt(env, CPU_INTERRUPT_HARD);
275             }
276         }
277     }
278 }
279
280 /*
281  * "irq" here is the bit number in the system interrupt register to
282  * separate serial and keyboard interrupts sharing a level.
283  */
284 void slavio_pic_set_irq(void *opaque, int irq, int level)
285 {
286     SLAVIO_INTCTLState *s = opaque;
287
288     DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
289     if (irq < 32) {
290         uint32_t mask = 1 << irq;
291         uint32_t pil = intbit_to_level[irq];
292         if (pil > 0) {
293             if (level) {
294                 s->intregm_pending |= mask;
295                 s->intreg_pending[s->target_cpu] |= 1 << pil;
296             }
297             else {
298                 s->intregm_pending &= ~mask;
299                 s->intreg_pending[s->target_cpu] &= ~(1 << pil);
300             }
301         }
302     }
303     slavio_check_interrupts(s);
304 }
305
306 void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
307 {
308     SLAVIO_INTCTLState *s = opaque;
309
310     DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
311     if (cpu == (unsigned int)-1) {
312         slavio_pic_set_irq(opaque, irq, level);
313         return;
314     }
315     if (irq < 32) {
316         uint32_t pil = intbit_to_level[irq];
317         if (pil > 0) {
318             if (level) {
319                 s->intreg_pending[cpu] |= 1 << pil;
320             }
321             else {
322                 s->intreg_pending[cpu] &= ~(1 << pil);
323             }
324         }
325     }
326     slavio_check_interrupts(s);
327 }
328
329 static void slavio_intctl_save(QEMUFile *f, void *opaque)
330 {
331     SLAVIO_INTCTLState *s = opaque;
332     int i;
333     
334     for (i = 0; i < MAX_CPUS; i++) {
335         qemu_put_be32s(f, &s->intreg_pending[i]);
336     }
337     qemu_put_be32s(f, &s->intregm_pending);
338     qemu_put_be32s(f, &s->intregm_disabled);
339     qemu_put_be32s(f, &s->target_cpu);
340 }
341
342 static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
343 {
344     SLAVIO_INTCTLState *s = opaque;
345     int i;
346
347     if (version_id != 1)
348         return -EINVAL;
349
350     for (i = 0; i < MAX_CPUS; i++) {
351         qemu_get_be32s(f, &s->intreg_pending[i]);
352     }
353     qemu_get_be32s(f, &s->intregm_pending);
354     qemu_get_be32s(f, &s->intregm_disabled);
355     qemu_get_be32s(f, &s->target_cpu);
356     return 0;
357 }
358
359 static void slavio_intctl_reset(void *opaque)
360 {
361     SLAVIO_INTCTLState *s = opaque;
362     int i;
363
364     for (i = 0; i < MAX_CPUS; i++) {
365         s->intreg_pending[i] = 0;
366     }
367     s->intregm_disabled = ~0xffb2007f;
368     s->intregm_pending = 0;
369     s->target_cpu = 0;
370 }
371
372 void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
373 {
374     SLAVIO_INTCTLState *s = opaque;
375     s->cpu_envs[cpu] = env;
376 }
377
378 void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
379 {
380     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
381     SLAVIO_INTCTLState *s;
382
383     s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
384     if (!s)
385         return NULL;
386
387     for (i = 0; i < MAX_CPUS; i++) {
388         slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
389         cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
390     }
391
392     slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
393     cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
394
395     register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
396     qemu_register_reset(slavio_intctl_reset, s);
397     slavio_intctl_reset(s);
398     return s;
399 }
400