/[qemu]/qemu/hw/apic.c
ViewVC logotype

Diff of /qemu/hw/apic.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by bellard, Sun Jan 23 20:42:29 2005 UTC revision 1.3 by bellard, Sat Jul 23 19:05:37 2005 UTC
# Line 20  Line 20 
20  #include "vl.h"  #include "vl.h"
21    
22  //#define DEBUG_APIC  //#define DEBUG_APIC
23    //#define DEBUG_IOAPIC
24    
25  /* APIC Local Vector Table */  /* APIC Local Vector Table */
26  #define APIC_LVT_TIMER   0  #define APIC_LVT_TIMER   0
# Line 39  Line 40 
40  #define APIC_DM_SIPI    6  #define APIC_DM_SIPI    6
41  #define APIC_DM_EXTINT  7  #define APIC_DM_EXTINT  7
42    
43    /* APIC destination mode */
44    #define APIC_DESTMODE_FLAT      0xf
45    #define APIC_DESTMODE_CLUSTER   1
46    
47  #define APIC_TRIGGER_EDGE  0  #define APIC_TRIGGER_EDGE  0
48  #define APIC_TRIGGER_LEVEL 1  #define APIC_TRIGGER_LEVEL 1
49    
# Line 49  Line 54 
54  #define APIC_INPUT_POLARITY             (1<<13)  #define APIC_INPUT_POLARITY             (1<<13)
55  #define APIC_SEND_PENDING               (1<<12)  #define APIC_SEND_PENDING               (1<<12)
56    
57    #define IOAPIC_NUM_PINS                 0x18
58    
59  #define ESR_ILLEGAL_ADDRESS (1 << 7)  #define ESR_ILLEGAL_ADDRESS (1 << 7)
60    
61  #define APIC_SV_ENABLE (1 << 8)  #define APIC_SV_ENABLE (1 << 8)
# Line 57  typedef struct APICState { Line 64  typedef struct APICState {
64      CPUState *cpu_env;      CPUState *cpu_env;
65      uint32_t apicbase;      uint32_t apicbase;
66      uint8_t id;      uint8_t id;
67        uint8_t arb_id;
68      uint8_t tpr;      uint8_t tpr;
69      uint32_t spurious_vec;      uint32_t spurious_vec;
70        uint8_t log_dest;
71        uint8_t dest_mode;
72      uint32_t isr[8];  /* in service register */      uint32_t isr[8];  /* in service register */
73      uint32_t tmr[8];  /* trigger mode register */      uint32_t tmr[8];  /* trigger mode register */
74      uint32_t irr[8]; /* interrupt request register */      uint32_t irr[8]; /* interrupt request register */
# Line 71  typedef struct APICState { Line 81  typedef struct APICState {
81      uint32_t initial_count;      uint32_t initial_count;
82      int64_t initial_count_load_time, next_time;      int64_t initial_count_load_time, next_time;
83      QEMUTimer *timer;      QEMUTimer *timer;
84    
85        struct APICState *next_apic;
86  } APICState;  } APICState;
87    
88    struct IOAPICState {
89        uint8_t id;
90        uint8_t ioregsel;
91    
92        uint32_t irr;
93        uint64_t ioredtbl[IOAPIC_NUM_PINS];
94    };
95    
96  static int apic_io_memory;  static int apic_io_memory;
97    static APICState *first_local_apic = NULL;
98    static int last_apic_id = 0;
99    static IOAPICState *ioapic_state;
100    
101    static void apic_init_ipi(APICState *s);
102    static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
103    static void apic_update_irq(APICState *s);
104    
105    static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
106                                 uint8_t vector_num, uint8_t polarity,
107                                 uint8_t trigger_mode)
108    {
109        APICState *apic_iter;
110    
111        switch (delivery_mode) {
112            case APIC_DM_LOWPRI:
113            case APIC_DM_FIXED:
114                /* XXX: arbitration */
115                break;
116    
117            case APIC_DM_SMI:
118            case APIC_DM_NMI:
119                break;
120    
121            case APIC_DM_INIT:
122                /* normal INIT IPI sent to processors */
123                for (apic_iter = first_local_apic; apic_iter != NULL;
124                     apic_iter = apic_iter->next_apic) {
125                    apic_init_ipi(apic_iter);
126                }
127                return;
128        
129            case APIC_DM_EXTINT:
130                /* XXX: implement */
131                break;
132    
133            default:
134                return;
135        }
136    
137        for (apic_iter = first_local_apic; apic_iter != NULL;
138             apic_iter = apic_iter->next_apic) {
139            if (deliver_bitmask & (1 << apic_iter->id))
140                apic_set_irq(apic_iter, vector_num, trigger_mode);
141        }
142    }
143    
144  void cpu_set_apic_base(CPUState *env, uint64_t val)  void cpu_set_apic_base(CPUState *env, uint64_t val)
145  {  {
# Line 104  void cpu_set_apic_tpr(CPUX86State *env, Line 170  void cpu_set_apic_tpr(CPUX86State *env,
170  {  {
171      APICState *s = env->apic_state;      APICState *s = env->apic_state;
172      s->tpr = (val & 0x0f) << 4;      s->tpr = (val & 0x0f) << 4;
173        apic_update_irq(s);
174  }  }
175    
176  uint8_t cpu_get_apic_tpr(CPUX86State *env)  uint8_t cpu_get_apic_tpr(CPUX86State *env)
# Line 112  uint8_t cpu_get_apic_tpr(CPUX86State *en Line 179  uint8_t cpu_get_apic_tpr(CPUX86State *en
179      return s->tpr >> 4;      return s->tpr >> 4;
180  }  }
181    
182  /* return -1 if no bit is set */  int fls_bit(int value)
 static int get_highest_priority_int(uint32_t *tab)  
183  {  {
184      int i;      unsigned int ret = 0;
185      for(i = 0;i < 8; i++) {  
186          if (tab[i] != 0) {  #ifdef HOST_I386
187              return i * 32 + ffs(tab[i]) - 1;      __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
188          }      return ret;
189      }  #else
190      return -1;      if (value > 0xffff)
191            value >>= 16, ret = 16;
192        if (value > 0xff)
193            value >>= 8, ret += 8;
194        if (value > 0xf)
195            value >>= 4, ret += 4;
196        if (value > 0x3)
197            value >>= 2, ret += 2;
198        return ret + (value >> 1);
199    #endif
200  }  }
201    
202  static inline void set_bit(uint32_t *tab, int index)  static inline void set_bit(uint32_t *tab, int index)
# Line 140  static inline void reset_bit(uint32_t *t Line 215  static inline void reset_bit(uint32_t *t
215      tab[i] &= ~mask;      tab[i] &= ~mask;
216  }  }
217    
218    /* return -1 if no bit is set */
219    static int get_highest_priority_int(uint32_t *tab)
220    {
221        int i;
222        for(i = 7; i >= 0; i--) {
223            if (tab[i] != 0) {
224                return i * 32 + fls_bit(tab[i]);
225            }
226        }
227        return -1;
228    }
229    
230  static int apic_get_ppr(APICState *s)  static int apic_get_ppr(APICState *s)
231  {  {
232      int tpr, isrv, ppr;      int tpr, isrv, ppr;
# Line 156  static int apic_get_ppr(APICState *s) Line 243  static int apic_get_ppr(APICState *s)
243      return ppr;      return ppr;
244  }  }
245    
246    static int apic_get_arb_pri(APICState *s)
247    {
248        /* XXX: arbitration */
249        return 0;
250    }
251    
252  /* signal the CPU if an irq is pending */  /* signal the CPU if an irq is pending */
253  static void apic_update_irq(APICState *s)  static void apic_update_irq(APICState *s)
254  {  {
255      int irrv, isrv;      int irrv, ppr;
256        if (!(s->spurious_vec & APIC_SV_ENABLE))
257            return;
258      irrv = get_highest_priority_int(s->irr);      irrv = get_highest_priority_int(s->irr);
259      if (irrv < 0)      if (irrv < 0)
260          return;          return;
261      isrv = get_highest_priority_int(s->isr);      ppr = apic_get_ppr(s);
262      /* if the pending irq has less priority, we do not make a new request */      if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
     if (isrv >= 0 && irrv >= isrv)  
263          return;          return;
264      cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);      cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
265  }  }
# Line 187  static void apic_eoi(APICState *s) Line 281  static void apic_eoi(APICState *s)
281      if (isrv < 0)      if (isrv < 0)
282          return;          return;
283      reset_bit(s->isr, isrv);      reset_bit(s->isr, isrv);
284        /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
285                set the remote IRR bit for level triggered interrupts. */
286      apic_update_irq(s);      apic_update_irq(s);
287  }  }
288    
289    static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
290    {
291        uint32_t mask = 0;
292        APICState *apic_iter;
293    
294        if (dest_mode == 0) {
295            if (dest == 0xff)
296                mask = 0xff;
297            else
298                mask = 1 << dest;
299        } else {
300            /* XXX: cluster mode */
301            for (apic_iter = first_local_apic; apic_iter != NULL;
302                 apic_iter = apic_iter->next_apic) {
303                if (dest & apic_iter->log_dest)
304                    mask |= (1 << apic_iter->id);
305            }
306        }
307    
308        return mask;
309    }
310    
311    
312    static void apic_init_ipi(APICState *s)
313    {
314        int i;
315    
316        for(i = 0; i < APIC_LVT_NB; i++)
317            s->lvt[i] = 1 << 16; /* mask LVT */
318        s->tpr = 0;
319        s->spurious_vec = 0xff;
320        s->log_dest = 0;
321        s->dest_mode = 0;
322        memset(s->isr, 0, sizeof(s->isr));
323        memset(s->tmr, 0, sizeof(s->tmr));
324        memset(s->irr, 0, sizeof(s->irr));
325        memset(s->lvt, 0, sizeof(s->lvt));
326        s->esr = 0;
327        memset(s->icr, 0, sizeof(s->icr));
328        s->divide_conf = 0;
329        s->count_shift = 0;
330        s->initial_count = 0;
331        s->initial_count_load_time = 0;
332        s->next_time = 0;
333    }
334    
335    static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
336                             uint8_t delivery_mode, uint8_t vector_num,
337                             uint8_t polarity, uint8_t trigger_mode)
338    {
339        uint32_t deliver_bitmask = 0;
340        int dest_shorthand = (s->icr[0] >> 18) & 3;
341        APICState *apic_iter;
342    
343        switch (delivery_mode) {
344            case APIC_DM_LOWPRI:
345                /* XXX: serch for focus processor, arbitration */
346                dest = s->id;
347    
348            case APIC_DM_INIT:
349                {
350                    int trig_mode = (s->icr[0] >> 15) & 1;
351                    int level = (s->icr[0] >> 14) & 1;
352                    if (level == 0 && trig_mode == 1) {
353                        for (apic_iter = first_local_apic; apic_iter != NULL;
354                             apic_iter = apic_iter->next_apic) {
355                            if (deliver_bitmask & (1 << apic_iter->id)) {
356                                apic_iter->arb_id = apic_iter->id;
357                            }
358                        }
359                        return;
360                    }
361                }
362                break;
363    
364            case APIC_DM_SIPI:
365                for (apic_iter = first_local_apic; apic_iter != NULL;
366                     apic_iter = apic_iter->next_apic) {
367                    if (deliver_bitmask & (1 << apic_iter->id)) {
368                        /* XXX: SMP support */
369                        /* apic_startup(apic_iter); */
370                    }
371                }
372                return;
373        }
374    
375        switch (dest_shorthand) {
376            case 0:
377                deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
378                break;
379            case 1:
380                deliver_bitmask = (1 << s->id);
381                break;
382            case 2:
383                deliver_bitmask = 0xffffffff;
384                break;
385            case 3:
386                deliver_bitmask = 0xffffffff & ~(1 << s->id);
387                break;
388        }
389    
390        apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
391                         trigger_mode);
392    }
393    
394  int apic_get_interrupt(CPUState *env)  int apic_get_interrupt(CPUState *env)
395  {  {
396      APICState *s = env->apic_state;      APICState *s = env->apic_state;
# Line 207  int apic_get_interrupt(CPUState *env) Line 408  int apic_get_interrupt(CPUState *env)
408      if (intno < 0)      if (intno < 0)
409          return -1;          return -1;
410      reset_bit(s->irr, intno);      reset_bit(s->irr, intno);
411        if (s->tpr && intno <= s->tpr)
412            return s->spurious_vec & 0xff;
413      set_bit(s->isr, intno);      set_bit(s->isr, intno);
414      apic_update_irq(s);      apic_update_irq(s);
415      return intno;      return intno;
# Line 220  static uint32_t apic_get_current_count(A Line 423  static uint32_t apic_get_current_count(A
423          s->count_shift;          s->count_shift;
424      if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {      if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
425          /* periodic */          /* periodic */
426          val = s->initial_count - (d % (s->initial_count + 1));          val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
427      } else {      } else {
428          if (d >= s->initial_count)          if (d >= s->initial_count)
429              val = 0;              val = 0;
# Line 238  static void apic_timer_update(APICState Line 441  static void apic_timer_update(APICState
441          d = (current_time - s->initial_count_load_time) >>          d = (current_time - s->initial_count_load_time) >>
442              s->count_shift;              s->count_shift;
443          if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {          if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
444              d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);              d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
445          } else {          } else {
446              if (d >= s->initial_count)              if (d >= s->initial_count)
447                  goto no_timer;                  goto no_timer;
448              d = s->initial_count + 1;              d = (uint64_t)s->initial_count + 1;
449          }          }
450          next_time = s->initial_count_load_time + (d << s->count_shift);          next_time = s->initial_count_load_time + (d << s->count_shift);
451          qemu_mod_timer(s->timer, next_time);          qemu_mod_timer(s->timer, next_time);
# Line 304  static uint32_t apic_mem_readl(void *opa Line 507  static uint32_t apic_mem_readl(void *opa
507      case 0x08:      case 0x08:
508          val = s->tpr;          val = s->tpr;
509          break;          break;
510        case 0x09:
511            val = apic_get_arb_pri(s);
512            break;
513      case 0x0a:      case 0x0a:
514          /* ppr */          /* ppr */
515          val = apic_get_ppr(s);          val = apic_get_ppr(s);
516          break;          break;
517        case 0x0d:
518            val = s->log_dest << 24;
519            break;
520        case 0x0e:
521            val = s->dest_mode << 28;
522            break;
523      case 0x0f:      case 0x0f:
524          val = s->spurious_vec;          val = s->spurious_vec;
525          break;          break;
# Line 372  static void apic_mem_writel(void *opaque Line 584  static void apic_mem_writel(void *opaque
584          break;          break;
585      case 0x08:      case 0x08:
586          s->tpr = val;          s->tpr = val;
587            apic_update_irq(s);
588          break;          break;
589      case 0x0b: /* EOI */      case 0x0b: /* EOI */
590          apic_eoi(s);          apic_eoi(s);
591          break;          break;
592        case 0x0d:
593            s->log_dest = val >> 24;
594            break;
595        case 0x0e:
596            s->dest_mode = val >> 28;
597            break;
598      case 0x0f:      case 0x0f:
599          s->spurious_vec = val & 0x1ff;          s->spurious_vec = val & 0x1ff;
600            apic_update_irq(s);
601          break;          break;
602      case 0x30:      case 0x30:
603            s->icr[0] = val;
604            apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
605                         (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
606                         (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
607            break;
608      case 0x31:      case 0x31:
609          s->icr[index & 1] = val;          s->icr[1] = val;
610          break;          break;
611      case 0x32 ... 0x37:      case 0x32 ... 0x37:
612          {          {
# Line 410  static void apic_mem_writel(void *opaque Line 635  static void apic_mem_writel(void *opaque
635      }      }
636  }  }
637    
638    static void apic_save(QEMUFile *f, void *opaque)
639    {
640        APICState *s = opaque;
641        int i;
642    
643        qemu_put_be32s(f, &s->apicbase);
644        qemu_put_8s(f, &s->id);
645        qemu_put_8s(f, &s->arb_id);
646        qemu_put_8s(f, &s->tpr);
647        qemu_put_be32s(f, &s->spurious_vec);
648        qemu_put_8s(f, &s->log_dest);
649        qemu_put_8s(f, &s->dest_mode);
650        for (i = 0; i < 8; i++) {
651            qemu_put_be32s(f, &s->isr[i]);
652            qemu_put_be32s(f, &s->tmr[i]);
653            qemu_put_be32s(f, &s->irr[i]);
654        }
655        for (i = 0; i < APIC_LVT_NB; i++) {
656            qemu_put_be32s(f, &s->lvt[i]);
657        }
658        qemu_put_be32s(f, &s->esr);
659        qemu_put_be32s(f, &s->icr[0]);
660        qemu_put_be32s(f, &s->icr[1]);
661        qemu_put_be32s(f, &s->divide_conf);
662        qemu_put_be32s(f, &s->count_shift);
663        qemu_put_be32s(f, &s->initial_count);
664        qemu_put_be64s(f, &s->initial_count_load_time);
665        qemu_put_be64s(f, &s->next_time);
666    }
667    
668    static int apic_load(QEMUFile *f, void *opaque, int version_id)
669    {
670        APICState *s = opaque;
671        int i;
672    
673        if (version_id != 1)
674            return -EINVAL;
675    
676        /* XXX: what if the base changes? (registered memory regions) */
677        qemu_get_be32s(f, &s->apicbase);
678        qemu_get_8s(f, &s->id);
679        qemu_get_8s(f, &s->arb_id);
680        qemu_get_8s(f, &s->tpr);
681        qemu_get_be32s(f, &s->spurious_vec);
682        qemu_get_8s(f, &s->log_dest);
683        qemu_get_8s(f, &s->dest_mode);
684        for (i = 0; i < 8; i++) {
685            qemu_get_be32s(f, &s->isr[i]);
686            qemu_get_be32s(f, &s->tmr[i]);
687            qemu_get_be32s(f, &s->irr[i]);
688        }
689        for (i = 0; i < APIC_LVT_NB; i++) {
690            qemu_get_be32s(f, &s->lvt[i]);
691        }
692        qemu_get_be32s(f, &s->esr);
693        qemu_get_be32s(f, &s->icr[0]);
694        qemu_get_be32s(f, &s->icr[1]);
695        qemu_get_be32s(f, &s->divide_conf);
696        qemu_get_be32s(f, &s->count_shift);
697        qemu_get_be32s(f, &s->initial_count);
698        qemu_get_be64s(f, &s->initial_count_load_time);
699        qemu_get_be64s(f, &s->next_time);
700        return 0;
701    }
702    
703    static void apic_reset(void *opaque)
704    {
705        APICState *s = opaque;
706        apic_init_ipi(s);
707    }
708    
709  static CPUReadMemoryFunc *apic_mem_read[3] = {  static CPUReadMemoryFunc *apic_mem_read[3] = {
710      apic_mem_readb,      apic_mem_readb,
# Line 427  static CPUWriteMemoryFunc *apic_mem_writ Line 721  static CPUWriteMemoryFunc *apic_mem_writ
721  int apic_init(CPUState *env)  int apic_init(CPUState *env)
722  {  {
723      APICState *s;      APICState *s;
     int i;  
724    
725      s = malloc(sizeof(APICState));      s = qemu_mallocz(sizeof(APICState));
726      if (!s)      if (!s)
727          return -1;          return -1;
     memset(s, 0, sizeof(*s));  
728      env->apic_state = s;      env->apic_state = s;
729        apic_init_ipi(s);
730        s->id = last_apic_id++;
731      s->cpu_env = env;      s->cpu_env = env;
732      s->apicbase = 0xfee00000 |      s->apicbase = 0xfee00000 |
733          MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;          (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
     for(i = 0; i < APIC_LVT_NB; i++)  
         s->lvt[i] = 1 << 16; /* mask LVT */  
     s->spurious_vec = 0xff;  
734    
735        /* XXX: mapping more APICs at the same memory location */
736      if (apic_io_memory == 0) {      if (apic_io_memory == 0) {
737          /* NOTE: the APIC is directly connected to the CPU - it is not          /* NOTE: the APIC is directly connected to the CPU - it is not
738             on the global memory bus. */             on the global memory bus. */
739          apic_io_memory = cpu_register_io_memory(0, apic_mem_read,          apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
740                                                  apic_mem_write, NULL);                                                  apic_mem_write, NULL);
741          cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);          cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
742                                         apic_io_memory);
743      }      }
744      s->timer = qemu_new_timer(vm_clock, apic_timer, s);      s->timer = qemu_new_timer(vm_clock, apic_timer, s);
745    
746        register_savevm("apic", 0, 1, apic_save, apic_load, s);
747        qemu_register_reset(apic_reset, s);
748    
749        s->next_apic = first_local_apic;
750        first_local_apic = s;
751        
752        return 0;
753    }
754    
755    static void ioapic_service(IOAPICState *s)
756    {
757        uint8_t vector;
758        uint32_t mask;
759        uint64_t entry;
760        uint8_t dest;
761        uint8_t dest_mode;
762    
763        for (vector = 0; vector < IOAPIC_NUM_PINS; vector++) {
764            mask = 1 << vector;
765            if (s->irr & mask) {
766                entry = s->ioredtbl[vector];
767                if (!(entry & APIC_LVT_MASKED)) {
768                    if (!((entry >> 15) & 1))
769                        s->irr &= ~mask;
770                    dest = entry >> 56;
771                    dest_mode = (entry >> 11) & 1;
772                    apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
773                                     (entry >> 8) & 7, entry & 0xff,
774                                     (entry >> 13) & 1, (entry >> 15) & 1);
775                }
776            }
777        }
778    }
779    
780    void ioapic_set_irq(void *opaque, int vector, int level)
781    {
782        IOAPICState *s = opaque;
783    
784        if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
785            uint32_t mask = 1 << vector;
786            uint64_t entry = s->ioredtbl[vector];
787    
788            if ((entry >> 15) & 1) {
789                /* level triggered */
790                if (level) {
791                    s->irr |= mask;
792                    ioapic_service(s);
793                } else {
794                    s->irr &= ~mask;
795                }
796            } else {
797                /* edge triggered */
798                if (level) {
799                    s->irr |= mask;
800                    ioapic_service(s);
801                }
802            }
803        }
804    }
805    
806    static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
807    {
808        IOAPICState *s = opaque;
809        int index;
810        uint32_t val = 0;
811    
812        addr &= 0xff;
813        if (addr == 0x00) {
814            val = s->ioregsel;
815        } else if (addr == 0x10) {
816            switch (s->ioregsel) {
817                case 0x00:
818                    val = s->id << 24;
819                    break;
820                case 0x01:
821                    val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
822                    break;
823                case 0x02:
824                    val = 0;
825                    break;
826                default:
827                    index = (s->ioregsel - 0x10) >> 1;
828                    if (index >= 0 && index < IOAPIC_NUM_PINS) {
829                        if (s->ioregsel & 1)
830                            val = s->ioredtbl[index] >> 32;
831                        else
832                            val = s->ioredtbl[index] & 0xffffffff;
833                    }
834            }
835    #ifdef DEBUG_IOAPIC
836            printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
837    #endif
838        }
839        return val;
840    }
841    
842    static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
843    {
844        IOAPICState *s = opaque;
845        int index;
846    
847        addr &= 0xff;
848        if (addr == 0x00)  {
849            s->ioregsel = val;
850            return;
851        } else if (addr == 0x10) {
852    #ifdef DEBUG_IOAPIC
853            printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
854    #endif
855            switch (s->ioregsel) {
856                case 0x00:
857                    s->id = (val >> 24) & 0xff;
858                    return;
859                case 0x01:
860                case 0x02:
861                    return;
862                default:
863                    index = (s->ioregsel - 0x10) >> 1;
864                    if (index >= 0 && index < IOAPIC_NUM_PINS) {
865                        if (s->ioregsel & 1) {
866                            s->ioredtbl[index] &= 0xffffffff;
867                            s->ioredtbl[index] |= (uint64_t)val << 32;
868                        } else {
869                            s->ioredtbl[index] &= ~0xffffffffULL;
870                            s->ioredtbl[index] |= val;
871                        }
872                        ioapic_service(s);
873                    }
874            }
875        }
876    }
877    
878    static void ioapic_save(QEMUFile *f, void *opaque)
879    {
880        IOAPICState *s = opaque;
881        int i;
882    
883        qemu_put_8s(f, &s->id);
884        qemu_put_8s(f, &s->ioregsel);
885        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
886            qemu_put_be64s(f, &s->ioredtbl[i]);
887        }
888    }
889    
890    static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
891    {
892        IOAPICState *s = opaque;
893        int i;
894    
895        if (version_id != 1)
896            return -EINVAL;
897    
898        qemu_get_8s(f, &s->id);
899        qemu_get_8s(f, &s->ioregsel);
900        for (i = 0; i < IOAPIC_NUM_PINS; i++) {
901            qemu_get_be64s(f, &s->ioredtbl[i]);
902        }
903      return 0;      return 0;
904  }  }
905    
906    static void ioapic_reset(void *opaque)
907    {
908        IOAPICState *s = opaque;
909        int i;
910    
911        memset(s, 0, sizeof(*s));
912        for(i = 0; i < IOAPIC_NUM_PINS; i++)
913            s->ioredtbl[i] = 1 << 16; /* mask LVT */
914    }
915    
916    static CPUReadMemoryFunc *ioapic_mem_read[3] = {
917        ioapic_mem_readl,
918        ioapic_mem_readl,
919        ioapic_mem_readl,
920    };
921    
922    static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
923        ioapic_mem_writel,
924        ioapic_mem_writel,
925        ioapic_mem_writel,
926    };
927    
928    IOAPICState *ioapic_init(void)
929    {
930        IOAPICState *s;
931        int io_memory;
932    
933        s = malloc(sizeof(IOAPICState));
934        if (!s)
935            return NULL;
936        ioapic_state = s;
937        ioapic_reset(s);
938        s->id = last_apic_id++;
939    
940        io_memory = cpu_register_io_memory(0, ioapic_mem_read,
941                                           ioapic_mem_write, s);
942        cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
943    
944        register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
945        qemu_register_reset(ioapic_reset, s);
946        
947        return s;
948    }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26