Commit ba3c64fb476d57c35013970ac444f04f35893ca9
1 parent
b9788fc4
Initial SPARC SMP support (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1694 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
12 changed files
with
196 additions
and
54 deletions
Changelog
cpu-all.h
| ... | ... | @@ -734,6 +734,7 @@ extern int code_copy_enabled; |
| 734 | 734 | #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ |
| 735 | 735 | #define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ |
| 736 | 736 | #define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ |
| 737 | +#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ | |
| 737 | 738 | |
| 738 | 739 | void cpu_interrupt(CPUState *s, int mask); |
| 739 | 740 | void cpu_reset_interrupt(CPUState *env, int mask); | ... | ... |
cpu-exec.c
| ... | ... | @@ -274,6 +274,15 @@ int cpu_exec(CPUState *env1) |
| 274 | 274 | return EXCP_HALTED; |
| 275 | 275 | } |
| 276 | 276 | } |
| 277 | +#elif defined(TARGET_SPARC) | |
| 278 | + if (env1->halted) { | |
| 279 | + if ((env1->interrupt_request & CPU_INTERRUPT_HARD) && | |
| 280 | + (env1->psret != 0)) { | |
| 281 | + env1->halted = 0; | |
| 282 | + } else { | |
| 283 | + return EXCP_HALTED; | |
| 284 | + } | |
| 285 | + } | |
| 277 | 286 | #elif defined(TARGET_ARM) |
| 278 | 287 | if (env1->halted) { |
| 279 | 288 | /* An interrupt wakes the CPU even if the I and F CPSR bits are |
| ... | ... | @@ -522,7 +531,10 @@ int cpu_exec(CPUState *env1) |
| 522 | 531 | } else if (interrupt_request & CPU_INTERRUPT_TIMER) { |
| 523 | 532 | //do_interrupt(0, 0, 0, 0, 0); |
| 524 | 533 | env->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
| 525 | - } | |
| 534 | + } else if (interrupt_request & CPU_INTERRUPT_HALT) { | |
| 535 | + env1->halted = 1; | |
| 536 | + return EXCP_HALTED; | |
| 537 | + } | |
| 526 | 538 | #elif defined(TARGET_ARM) |
| 527 | 539 | if (interrupt_request & CPU_INTERRUPT_FIQ |
| 528 | 540 | && !(env->uncached_cpsr & CPSR_F)) { | ... | ... |
hw/slavio_intctl.c
| ... | ... | @@ -53,6 +53,7 @@ typedef struct SLAVIO_INTCTLState { |
| 53 | 53 | #ifdef DEBUG_IRQ_COUNT |
| 54 | 54 | uint64_t irq_count[32]; |
| 55 | 55 | #endif |
| 56 | + CPUState *cpu_envs[MAX_CPUS]; | |
| 56 | 57 | } SLAVIO_INTCTLState; |
| 57 | 58 | |
| 58 | 59 | #define INTCTL_MAXADDR 0xf |
| ... | ... | @@ -96,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint |
| 96 | 97 | case 2: // set softint |
| 97 | 98 | val &= 0xfffe0000; |
| 98 | 99 | s->intreg_pending[cpu] |= val; |
| 100 | + slavio_check_interrupts(s); | |
| 99 | 101 | DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); |
| 100 | 102 | break; |
| 101 | 103 | default: |
| ... | ... | @@ -216,7 +218,7 @@ static void slavio_check_interrupts(void *opaque) |
| 216 | 218 | CPUState *env; |
| 217 | 219 | SLAVIO_INTCTLState *s = opaque; |
| 218 | 220 | uint32_t pending = s->intregm_pending; |
| 219 | - unsigned int i, max = 0; | |
| 221 | + unsigned int i, j, max = 0; | |
| 220 | 222 | |
| 221 | 223 | pending &= ~s->intregm_disabled; |
| 222 | 224 | |
| ... | ... | @@ -227,20 +229,52 @@ static void slavio_check_interrupts(void *opaque) |
| 227 | 229 | max = intbit_to_level[i]; |
| 228 | 230 | } |
| 229 | 231 | } |
| 230 | - env = first_cpu; | |
| 231 | - if (env->interrupt_index == 0) { | |
| 232 | - DPRINTF("Triggered pil %d\n", max); | |
| 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); | |
| 233 | 241 | #ifdef DEBUG_IRQ_COUNT |
| 234 | - s->irq_count[max]++; | |
| 242 | + s->irq_count[max]++; | |
| 235 | 243 | #endif |
| 236 | - env->interrupt_index = TT_EXTINT | max; | |
| 237 | - cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
| 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); | |
| 238 | 249 | } |
| 239 | - else | |
| 240 | - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); | |
| 241 | 250 | } |
| 242 | 251 | else |
| 243 | 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 | + } | |
| 244 | 278 | } |
| 245 | 279 | |
| 246 | 280 | /* |
| ... | ... | @@ -251,7 +285,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) |
| 251 | 285 | { |
| 252 | 286 | SLAVIO_INTCTLState *s = opaque; |
| 253 | 287 | |
| 254 | - DPRINTF("Set irq %d level %d\n", irq, level); | |
| 288 | + DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); | |
| 255 | 289 | if (irq < 32) { |
| 256 | 290 | uint32_t mask = 1 << irq; |
| 257 | 291 | uint32_t pil = intbit_to_level[irq]; |
| ... | ... | @@ -269,6 +303,29 @@ void slavio_pic_set_irq(void *opaque, int irq, int level) |
| 269 | 303 | slavio_check_interrupts(s); |
| 270 | 304 | } |
| 271 | 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 | + | |
| 272 | 329 | static void slavio_intctl_save(QEMUFile *f, void *opaque) |
| 273 | 330 | { |
| 274 | 331 | SLAVIO_INTCTLState *s = opaque; |
| ... | ... | @@ -312,6 +369,12 @@ static void slavio_intctl_reset(void *opaque) |
| 312 | 369 | s->target_cpu = 0; |
| 313 | 370 | } |
| 314 | 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 | + | |
| 315 | 378 | void *slavio_intctl_init(uint32_t addr, uint32_t addrg) |
| 316 | 379 | { |
| 317 | 380 | int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; | ... | ... |
hw/slavio_misc.c
| ... | ... | @@ -124,9 +124,8 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32 |
| 124 | 124 | case 0xa000000: |
| 125 | 125 | MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); |
| 126 | 126 | #if 0 |
| 127 | - // XXX: halting CPU does not work | |
| 128 | - raise_exception(EXCP_HLT); | |
| 129 | - cpu_loop_exit(); | |
| 127 | + // XXX almost works | |
| 128 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); | |
| 130 | 129 | #endif |
| 131 | 130 | break; |
| 132 | 131 | } | ... | ... |
hw/slavio_serial.c
| ... | ... | @@ -45,6 +45,8 @@ |
| 45 | 45 | #ifdef DEBUG_SERIAL |
| 46 | 46 | #define SER_DPRINTF(fmt, args...) \ |
| 47 | 47 | do { printf("SER: " fmt , ##args); } while (0) |
| 48 | +#define pic_set_irq(irq, level) \ | |
| 49 | +do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) | |
| 48 | 50 | #else |
| 49 | 51 | #define SER_DPRINTF(fmt, args...) |
| 50 | 52 | #endif |
| ... | ... | @@ -174,6 +176,50 @@ static void slavio_serial_reset(void *opaque) |
| 174 | 176 | slavio_serial_reset_chn(&s->chn[1]); |
| 175 | 177 | } |
| 176 | 178 | |
| 179 | +static inline void clr_rxint(ChannelState *s) | |
| 180 | +{ | |
| 181 | + s->rxint = 0; | |
| 182 | + if (s->chn == 0) | |
| 183 | + s->rregs[3] &= ~0x20; | |
| 184 | + else { | |
| 185 | + s->otherchn->rregs[3] &= ~4; | |
| 186 | + } | |
| 187 | + slavio_serial_update_irq(s); | |
| 188 | +} | |
| 189 | + | |
| 190 | +static inline void set_rxint(ChannelState *s) | |
| 191 | +{ | |
| 192 | + s->rxint = 1; | |
| 193 | + if (s->chn == 0) | |
| 194 | + s->rregs[3] |= 0x20; | |
| 195 | + else { | |
| 196 | + s->otherchn->rregs[3] |= 4; | |
| 197 | + } | |
| 198 | + slavio_serial_update_irq(s); | |
| 199 | +} | |
| 200 | + | |
| 201 | +static inline void clr_txint(ChannelState *s) | |
| 202 | +{ | |
| 203 | + s->txint = 0; | |
| 204 | + if (s->chn == 0) | |
| 205 | + s->rregs[3] &= ~0x10; | |
| 206 | + else { | |
| 207 | + s->otherchn->rregs[3] &= ~2; | |
| 208 | + } | |
| 209 | + slavio_serial_update_irq(s); | |
| 210 | +} | |
| 211 | + | |
| 212 | +static inline void set_txint(ChannelState *s) | |
| 213 | +{ | |
| 214 | + s->txint = 1; | |
| 215 | + if (s->chn == 0) | |
| 216 | + s->rregs[3] |= 0x10; | |
| 217 | + else { | |
| 218 | + s->otherchn->rregs[3] |= 2; | |
| 219 | + } | |
| 220 | + slavio_serial_update_irq(s); | |
| 221 | +} | |
| 222 | + | |
| 177 | 223 | static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
| 178 | 224 | { |
| 179 | 225 | SerialState *ser = opaque; |
| ... | ... | @@ -198,10 +244,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
| 198 | 244 | newreg |= 0x8; |
| 199 | 245 | break; |
| 200 | 246 | case 0x20: |
| 201 | - s->rxint = 0; | |
| 247 | + clr_rxint(s); | |
| 202 | 248 | break; |
| 203 | 249 | case 0x28: |
| 204 | - s->txint = 0; | |
| 250 | + clr_txint(s); | |
| 251 | + break; | |
| 252 | + case 0x38: | |
| 253 | + clr_rxint(s); | |
| 254 | + clr_txint(s); | |
| 205 | 255 | break; |
| 206 | 256 | default: |
| 207 | 257 | break; |
| ... | ... | @@ -247,12 +297,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
| 247 | 297 | s->txint = 1; |
| 248 | 298 | s->rregs[0] |= 4; // Tx buffer empty |
| 249 | 299 | s->rregs[1] |= 1; // All sent |
| 250 | - // Interrupts reported only on channel A | |
| 251 | - if (s->chn == 0) | |
| 252 | - s->rregs[3] |= 0x10; | |
| 253 | - else { | |
| 254 | - s->otherchn->rregs[3] |= 2; | |
| 255 | - } | |
| 300 | + set_txint(s); | |
| 256 | 301 | slavio_serial_update_irq(s); |
| 257 | 302 | } |
| 258 | 303 | break; |
| ... | ... | @@ -280,6 +325,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) |
| 280 | 325 | return ret; |
| 281 | 326 | case 1: |
| 282 | 327 | s->rregs[0] &= ~1; |
| 328 | + clr_rxint(s); | |
| 283 | 329 | if (s->type == kbd) |
| 284 | 330 | ret = get_queue(s); |
| 285 | 331 | else |
| ... | ... | @@ -304,16 +350,10 @@ static int serial_can_receive(void *opaque) |
| 304 | 350 | |
| 305 | 351 | static void serial_receive_byte(ChannelState *s, int ch) |
| 306 | 352 | { |
| 353 | + SER_DPRINTF("put ch %d\n", ch); | |
| 307 | 354 | s->rregs[0] |= 1; |
| 308 | - // Interrupts reported only on channel A | |
| 309 | - if (s->chn == 0) | |
| 310 | - s->rregs[3] |= 0x20; | |
| 311 | - else { | |
| 312 | - s->otherchn->rregs[3] |= 4; | |
| 313 | - } | |
| 314 | 355 | s->rx = ch; |
| 315 | - s->rxint = 1; | |
| 316 | - slavio_serial_update_irq(s); | |
| 356 | + set_rxint(s); | |
| 317 | 357 | } |
| 318 | 358 | |
| 319 | 359 | static void serial_receive_break(ChannelState *s) | ... | ... |
hw/slavio_timer.c
| ... | ... | @@ -42,6 +42,9 @@ do { printf("TIMER: " fmt , ##args); } while (0) |
| 42 | 42 | * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 |
| 43 | 43 | * are zero. Bit 31 is 1 when count has been reached. |
| 44 | 44 | * |
| 45 | + * Per-CPU timers interrupt local CPU, system timer uses normal | |
| 46 | + * interrupt routing. | |
| 47 | + * | |
| 45 | 48 | */ |
| 46 | 49 | |
| 47 | 50 | typedef struct SLAVIO_TIMERState { |
| ... | ... | @@ -53,11 +56,11 @@ typedef struct SLAVIO_TIMERState { |
| 53 | 56 | int irq; |
| 54 | 57 | int reached, stopped; |
| 55 | 58 | int mode; // 0 = processor, 1 = user, 2 = system |
| 59 | + unsigned int cpu; | |
| 56 | 60 | } SLAVIO_TIMERState; |
| 57 | 61 | |
| 58 | 62 | #define TIMER_MAXADDR 0x1f |
| 59 | 63 | #define CNT_FREQ 2000000 |
| 60 | -#define MAX_CPUS 16 | |
| 61 | 64 | |
| 62 | 65 | // Update count, set irq, update expire_time |
| 63 | 66 | static void slavio_timer_get_out(SLAVIO_TIMERState *s) |
| ... | ... | @@ -73,7 +76,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) |
| 73 | 76 | else |
| 74 | 77 | ticks = qemu_get_clock(vm_clock) - s->tick_offset; |
| 75 | 78 | |
| 76 | - out = (ticks >= s->expire_time); | |
| 79 | + out = (ticks > s->expire_time); | |
| 77 | 80 | if (out) |
| 78 | 81 | s->reached = 0x80000000; |
| 79 | 82 | if (!s->limit) |
| ... | ... | @@ -100,7 +103,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s) |
| 100 | 103 | DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); |
| 101 | 104 | |
| 102 | 105 | if (s->mode != 1) |
| 103 | - pic_set_irq(s->irq, out); | |
| 106 | + pic_set_irq_cpu(s->irq, out, s->cpu); | |
| 104 | 107 | } |
| 105 | 108 | |
| 106 | 109 | // timer callback |
| ... | ... | @@ -127,7 +130,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) |
| 127 | 130 | // part of counter (user mode) |
| 128 | 131 | if (s->mode != 1) { |
| 129 | 132 | // clear irq |
| 130 | - pic_set_irq(s->irq, 0); | |
| 133 | + pic_set_irq_cpu(s->irq, 0, s->cpu); | |
| 131 | 134 | s->count_load_time = qemu_get_clock(vm_clock); |
| 132 | 135 | s->reached = 0; |
| 133 | 136 | return s->limit; |
| ... | ... | @@ -263,7 +266,7 @@ static void slavio_timer_reset(void *opaque) |
| 263 | 266 | slavio_timer_get_out(s); |
| 264 | 267 | } |
| 265 | 268 | |
| 266 | -static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) | |
| 269 | +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu) | |
| 267 | 270 | { |
| 268 | 271 | int slavio_timer_io_memory; |
| 269 | 272 | SLAVIO_TIMERState *s; |
| ... | ... | @@ -273,6 +276,7 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) |
| 273 | 276 | return; |
| 274 | 277 | s->irq = irq; |
| 275 | 278 | s->mode = mode; |
| 279 | + s->cpu = cpu; | |
| 276 | 280 | s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); |
| 277 | 281 | |
| 278 | 282 | slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, |
| ... | ... | @@ -282,14 +286,3 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode) |
| 282 | 286 | qemu_register_reset(slavio_timer_reset, s); |
| 283 | 287 | slavio_timer_reset(s); |
| 284 | 288 | } |
| 285 | - | |
| 286 | -void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2) | |
| 287 | -{ | |
| 288 | - int i; | |
| 289 | - | |
| 290 | - for (i = 0; i < MAX_CPUS; i++) { | |
| 291 | - slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0); | |
| 292 | - } | |
| 293 | - | |
| 294 | - slavio_timer_init_internal(addr2, irq2, 2); | |
| 295 | -} | ... | ... |
hw/sun4m.c
| ... | ... | @@ -56,6 +56,7 @@ |
| 56 | 56 | #define PHYS_JJ_FDC 0x71400000 /* Floppy */ |
| 57 | 57 | #define PHYS_JJ_FLOPPY_IRQ 22 |
| 58 | 58 | #define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ |
| 59 | +#define MAX_CPUS 16 | |
| 59 | 60 | |
| 60 | 61 | /* TSC handling */ |
| 61 | 62 | |
| ... | ... | @@ -128,6 +129,8 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, |
| 128 | 129 | nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); |
| 129 | 130 | nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ |
| 130 | 131 | // NVRAM_size, arch not applicable |
| 132 | + m48t59_write(nvram, 0x2D, smp_cpus & 0xff); | |
| 133 | + m48t59_write(nvram, 0x2E, 0); | |
| 131 | 134 | m48t59_write(nvram, 0x2F, nographic & 0xff); |
| 132 | 135 | nvram_set_lword(nvram, 0x30, RAM_size); |
| 133 | 136 | m48t59_write(nvram, 0x34, boot_device & 0xff); |
| ... | ... | @@ -179,6 +182,11 @@ void pic_set_irq(int irq, int level) |
| 179 | 182 | slavio_pic_set_irq(slavio_intctl, irq, level); |
| 180 | 183 | } |
| 181 | 184 | |
| 185 | +void pic_set_irq_cpu(int irq, int level, unsigned int cpu) | |
| 186 | +{ | |
| 187 | + slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); | |
| 188 | +} | |
| 189 | + | |
| 182 | 190 | static void *tcx; |
| 183 | 191 | |
| 184 | 192 | void vga_update_display() |
| ... | ... | @@ -222,7 +230,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, |
| 222 | 230 | const char *kernel_filename, const char *kernel_cmdline, |
| 223 | 231 | const char *initrd_filename) |
| 224 | 232 | { |
| 225 | - CPUState *env; | |
| 233 | + CPUState *env, *envs[MAX_CPUS]; | |
| 226 | 234 | char buf[1024]; |
| 227 | 235 | int ret, linux_boot; |
| 228 | 236 | unsigned int i; |
| ... | ... | @@ -230,19 +238,31 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, |
| 230 | 238 | |
| 231 | 239 | linux_boot = (kernel_filename != NULL); |
| 232 | 240 | |
| 233 | - env = cpu_init(); | |
| 234 | - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
| 235 | - qemu_register_reset(main_cpu_reset, env); | |
| 236 | - | |
| 241 | + /* init CPUs */ | |
| 242 | + for(i = 0; i < smp_cpus; i++) { | |
| 243 | + env = cpu_init(); | |
| 244 | + envs[i] = env; | |
| 245 | + if (i != 0) | |
| 246 | + env->halted = 1; | |
| 247 | + register_savevm("cpu", i, 3, cpu_save, cpu_load, env); | |
| 248 | + qemu_register_reset(main_cpu_reset, env); | |
| 249 | + } | |
| 237 | 250 | /* allocate RAM */ |
| 238 | 251 | cpu_register_physical_memory(0, ram_size, 0); |
| 239 | 252 | |
| 240 | 253 | iommu = iommu_init(PHYS_JJ_IOMMU); |
| 241 | 254 | slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); |
| 255 | + for(i = 0; i < smp_cpus; i++) { | |
| 256 | + slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); | |
| 257 | + } | |
| 258 | + | |
| 242 | 259 | tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); |
| 243 | 260 | lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); |
| 244 | 261 | nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); |
| 245 | - slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ); | |
| 262 | + for (i = 0; i < MAX_CPUS; i++) { | |
| 263 | + slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i); | |
| 264 | + } | |
| 265 | + slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1); | |
| 246 | 266 | slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); |
| 247 | 267 | // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device |
| 248 | 268 | // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device | ... | ... |
monitor.c
| ... | ... | @@ -259,6 +259,10 @@ static void do_info_cpus(void) |
| 259 | 259 | term_printf(" nip=0x" TARGET_FMT_lx, env->nip); |
| 260 | 260 | if (env->halted) |
| 261 | 261 | term_printf(" (halted)"); |
| 262 | +#elif defined(TARGET_SPARC) | |
| 263 | + term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); | |
| 264 | + if (env->halted) | |
| 265 | + term_printf(" (halted)"); | |
| 262 | 266 | #endif |
| 263 | 267 | term_printf("\n"); |
| 264 | 268 | } | ... | ... |
target-sparc/cpu.h
vl.c
| ... | ... | @@ -153,6 +153,11 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; |
| 153 | 153 | USBDevice *vm_usb_hub; |
| 154 | 154 | static VLANState *first_vlan; |
| 155 | 155 | int smp_cpus = 1; |
| 156 | +#ifdef TARGET_SPARC | |
| 157 | +#define MAX_CPUS 16 | |
| 158 | +#else | |
| 159 | +#define MAX_CPUS 8 | |
| 160 | +#endif | |
| 156 | 161 | |
| 157 | 162 | /***********************************************************/ |
| 158 | 163 | /* x86 ISA bus support */ |
| ... | ... | @@ -4547,7 +4552,7 @@ int main(int argc, char **argv) |
| 4547 | 4552 | break; |
| 4548 | 4553 | case QEMU_OPTION_smp: |
| 4549 | 4554 | smp_cpus = atoi(optarg); |
| 4550 | - if (smp_cpus < 1 || smp_cpus > 8) { | |
| 4555 | + if (smp_cpus < 1 || smp_cpus > MAX_CPUS) { | |
| 4551 | 4556 | fprintf(stderr, "Invalid number of CPUs\n"); |
| 4552 | 4557 | exit(1); |
| 4553 | 4558 | } | ... | ... |
vl.h
| ... | ... | @@ -806,6 +806,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); |
| 806 | 806 | /* sun4m.c */ |
| 807 | 807 | extern QEMUMachine sun4m_machine; |
| 808 | 808 | uint32_t iommu_translate(uint32_t addr); |
| 809 | +void pic_set_irq_cpu(int irq, int level, unsigned int cpu); | |
| 809 | 810 | |
| 810 | 811 | /* iommu.c */ |
| 811 | 812 | void *iommu_init(uint32_t addr); |
| ... | ... | @@ -823,16 +824,18 @@ void tcx_screen_dump(void *opaque, const char *filename); |
| 823 | 824 | |
| 824 | 825 | /* slavio_intctl.c */ |
| 825 | 826 | void *slavio_intctl_init(); |
| 827 | +void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env); | |
| 826 | 828 | void slavio_pic_info(void *opaque); |
| 827 | 829 | void slavio_irq_info(void *opaque); |
| 828 | 830 | void slavio_pic_set_irq(void *opaque, int irq, int level); |
| 831 | +void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu); | |
| 829 | 832 | |
| 830 | 833 | /* magic-load.c */ |
| 831 | 834 | int load_elf(const char *filename, uint8_t *addr); |
| 832 | 835 | int load_aout(const char *filename, uint8_t *addr); |
| 833 | 836 | |
| 834 | 837 | /* slavio_timer.c */ |
| 835 | -void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2); | |
| 838 | +void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu); | |
| 836 | 839 | |
| 837 | 840 | /* slavio_serial.c */ |
| 838 | 841 | SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2); | ... | ... |