Commit d3e9db933f416c9f1c04df4834d36e2315952e42
1 parent
01dbbdf1
initial support for up to 255 CPUs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1707 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
160 additions
and
100 deletions
hw/apic.c
... | ... | @@ -60,6 +60,9 @@ |
60 | 60 | |
61 | 61 | #define APIC_SV_ENABLE (1 << 8) |
62 | 62 | |
63 | +#define MAX_APICS 255 | |
64 | +#define MAX_APIC_WORDS 8 | |
65 | + | |
63 | 66 | typedef struct APICState { |
64 | 67 | CPUState *cpu_env; |
65 | 68 | uint32_t apicbase; |
... | ... | @@ -81,8 +84,6 @@ typedef struct APICState { |
81 | 84 | uint32_t initial_count; |
82 | 85 | int64_t initial_count_load_time, next_time; |
83 | 86 | QEMUTimer *timer; |
84 | - | |
85 | - struct APICState *next_apic; | |
86 | 87 | } APICState; |
87 | 88 | |
88 | 89 | struct IOAPICState { |
... | ... | @@ -94,14 +95,95 @@ struct IOAPICState { |
94 | 95 | }; |
95 | 96 | |
96 | 97 | static int apic_io_memory; |
97 | -static APICState *first_local_apic = NULL; | |
98 | +static APICState *local_apics[MAX_APICS + 1]; | |
98 | 99 | static int last_apic_id = 0; |
99 | 100 | |
100 | 101 | static void apic_init_ipi(APICState *s); |
101 | 102 | static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); |
102 | 103 | static void apic_update_irq(APICState *s); |
103 | 104 | |
104 | -static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, | |
105 | +/* Find first bit starting from msb. Return 0 if value = 0 */ | |
106 | +static int fls_bit(uint32_t value) | |
107 | +{ | |
108 | + unsigned int ret = 0; | |
109 | + | |
110 | +#if defined(HOST_I386) | |
111 | + __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); | |
112 | + return ret; | |
113 | +#else | |
114 | + if (value > 0xffff) | |
115 | + value >>= 16, ret = 16; | |
116 | + if (value > 0xff) | |
117 | + value >>= 8, ret += 8; | |
118 | + if (value > 0xf) | |
119 | + value >>= 4, ret += 4; | |
120 | + if (value > 0x3) | |
121 | + value >>= 2, ret += 2; | |
122 | + return ret + (value >> 1); | |
123 | +#endif | |
124 | +} | |
125 | + | |
126 | +/* Find first bit starting from lsb. Return 0 if value = 0 */ | |
127 | +static int ffs_bit(uint32_t value) | |
128 | +{ | |
129 | + unsigned int ret = 0; | |
130 | + | |
131 | +#if defined(HOST_I386) | |
132 | + __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value)); | |
133 | + return ret; | |
134 | +#else | |
135 | + if (!value) | |
136 | + return 0; | |
137 | + if (!(value & 0xffff)) | |
138 | + value >>= 16, ret = 16; | |
139 | + if (!(value & 0xff)) | |
140 | + value >>= 8, ret += 8; | |
141 | + if (!(value & 0xf)) | |
142 | + value >>= 4, ret += 4; | |
143 | + if (!(value & 0x3)) | |
144 | + value >>= 2, ret += 2; | |
145 | + if (!(value & 0x1)) | |
146 | + ret++; | |
147 | + return ret; | |
148 | +#endif | |
149 | +} | |
150 | + | |
151 | +static inline void set_bit(uint32_t *tab, int index) | |
152 | +{ | |
153 | + int i, mask; | |
154 | + i = index >> 5; | |
155 | + mask = 1 << (index & 0x1f); | |
156 | + tab[i] |= mask; | |
157 | +} | |
158 | + | |
159 | +static inline void reset_bit(uint32_t *tab, int index) | |
160 | +{ | |
161 | + int i, mask; | |
162 | + i = index >> 5; | |
163 | + mask = 1 << (index & 0x1f); | |
164 | + tab[i] &= ~mask; | |
165 | +} | |
166 | + | |
167 | +#define foreach_apic(apic, deliver_bitmask, code) \ | |
168 | +{\ | |
169 | + int __i, __j, __mask;\ | |
170 | + for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ | |
171 | + __mask = deliver_bitmask[__i];\ | |
172 | + if (__mask) {\ | |
173 | + for(__j = 0; __j < 32; __j++) {\ | |
174 | + if (__mask & (1 << __j)) {\ | |
175 | + apic = local_apics[__i * 32 + __j];\ | |
176 | + if (apic) {\ | |
177 | + code;\ | |
178 | + }\ | |
179 | + }\ | |
180 | + }\ | |
181 | + }\ | |
182 | + }\ | |
183 | +} | |
184 | + | |
185 | +static void apic_bus_deliver(const uint32_t *deliver_bitmask, | |
186 | + uint8_t delivery_mode, | |
105 | 187 | uint8_t vector_num, uint8_t polarity, |
106 | 188 | uint8_t trigger_mode) |
107 | 189 | { |
... | ... | @@ -110,13 +192,23 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, |
110 | 192 | switch (delivery_mode) { |
111 | 193 | case APIC_DM_LOWPRI: |
112 | 194 | /* XXX: search for focus processor, arbitration */ |
113 | - if (deliver_bitmask) { | |
114 | - uint32_t m = 1; | |
115 | - while ((deliver_bitmask & m) == 0) | |
116 | - m <<= 1; | |
117 | - deliver_bitmask = m; | |
195 | + { | |
196 | + int i, d; | |
197 | + d = -1; | |
198 | + for(i = 0; i < MAX_APIC_WORDS; i++) { | |
199 | + if (deliver_bitmask[i]) { | |
200 | + d = i * 32 + ffs_bit(deliver_bitmask[i]); | |
201 | + break; | |
202 | + } | |
203 | + } | |
204 | + if (d >= 0) { | |
205 | + apic_iter = local_apics[d]; | |
206 | + if (apic_iter) { | |
207 | + apic_set_irq(apic_iter, vector_num, trigger_mode); | |
208 | + } | |
209 | + } | |
118 | 210 | } |
119 | - break; | |
211 | + return; | |
120 | 212 | |
121 | 213 | case APIC_DM_FIXED: |
122 | 214 | break; |
... | ... | @@ -127,11 +219,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, |
127 | 219 | |
128 | 220 | case APIC_DM_INIT: |
129 | 221 | /* normal INIT IPI sent to processors */ |
130 | - for (apic_iter = first_local_apic; apic_iter != NULL; | |
131 | - apic_iter = apic_iter->next_apic) { | |
132 | - if (deliver_bitmask & (1 << apic_iter->id)) | |
133 | - apic_init_ipi(apic_iter); | |
134 | - } | |
222 | + foreach_apic(apic_iter, deliver_bitmask, | |
223 | + apic_init_ipi(apic_iter) ); | |
135 | 224 | return; |
136 | 225 | |
137 | 226 | case APIC_DM_EXTINT: |
... | ... | @@ -142,11 +231,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode, |
142 | 231 | return; |
143 | 232 | } |
144 | 233 | |
145 | - for (apic_iter = first_local_apic; apic_iter != NULL; | |
146 | - apic_iter = apic_iter->next_apic) { | |
147 | - if (deliver_bitmask & (1 << apic_iter->id)) | |
148 | - apic_set_irq(apic_iter, vector_num, trigger_mode); | |
149 | - } | |
234 | + foreach_apic(apic_iter, deliver_bitmask, | |
235 | + apic_set_irq(apic_iter, vector_num, trigger_mode) ); | |
150 | 236 | } |
151 | 237 | |
152 | 238 | void cpu_set_apic_base(CPUState *env, uint64_t val) |
... | ... | @@ -187,42 +273,6 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env) |
187 | 273 | return s->tpr >> 4; |
188 | 274 | } |
189 | 275 | |
190 | -static int fls_bit(int value) | |
191 | -{ | |
192 | - unsigned int ret = 0; | |
193 | - | |
194 | -#ifdef HOST_I386 | |
195 | - __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); | |
196 | - return ret; | |
197 | -#else | |
198 | - if (value > 0xffff) | |
199 | - value >>= 16, ret = 16; | |
200 | - if (value > 0xff) | |
201 | - value >>= 8, ret += 8; | |
202 | - if (value > 0xf) | |
203 | - value >>= 4, ret += 4; | |
204 | - if (value > 0x3) | |
205 | - value >>= 2, ret += 2; | |
206 | - return ret + (value >> 1); | |
207 | -#endif | |
208 | -} | |
209 | - | |
210 | -static inline void set_bit(uint32_t *tab, int index) | |
211 | -{ | |
212 | - int i, mask; | |
213 | - i = index >> 5; | |
214 | - mask = 1 << (index & 0x1f); | |
215 | - tab[i] |= mask; | |
216 | -} | |
217 | - | |
218 | -static inline void reset_bit(uint32_t *tab, int index) | |
219 | -{ | |
220 | - int i, mask; | |
221 | - i = index >> 5; | |
222 | - mask = 1 << (index & 0x1f); | |
223 | - tab[i] &= ~mask; | |
224 | -} | |
225 | - | |
226 | 276 | /* return -1 if no bit is set */ |
227 | 277 | static int get_highest_priority_int(uint32_t *tab) |
228 | 278 | { |
... | ... | @@ -294,26 +344,37 @@ static void apic_eoi(APICState *s) |
294 | 344 | apic_update_irq(s); |
295 | 345 | } |
296 | 346 | |
297 | -static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode) | |
347 | +static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, | |
348 | + uint8_t dest, uint8_t dest_mode) | |
298 | 349 | { |
299 | - uint32_t mask = 0; | |
300 | 350 | APICState *apic_iter; |
351 | + int i; | |
301 | 352 | |
302 | 353 | if (dest_mode == 0) { |
303 | - if (dest == 0xff) | |
304 | - mask = 0xff; | |
305 | - else | |
306 | - mask = 1 << dest; | |
354 | + if (dest == 0xff) { | |
355 | + memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); | |
356 | + } else { | |
357 | + memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); | |
358 | + set_bit(deliver_bitmask, dest); | |
359 | + } | |
307 | 360 | } else { |
308 | 361 | /* XXX: cluster mode */ |
309 | - for (apic_iter = first_local_apic; apic_iter != NULL; | |
310 | - apic_iter = apic_iter->next_apic) { | |
311 | - if (dest & apic_iter->log_dest) | |
312 | - mask |= (1 << apic_iter->id); | |
362 | + memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); | |
363 | + for(i = 0; i < MAX_APICS; i++) { | |
364 | + apic_iter = local_apics[i]; | |
365 | + if (apic_iter) { | |
366 | + if (apic_iter->dest_mode == 0xf) { | |
367 | + if (dest & apic_iter->log_dest) | |
368 | + set_bit(deliver_bitmask, i); | |
369 | + } else if (apic_iter->dest_mode == 0x0) { | |
370 | + if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && | |
371 | + (dest & apic_iter->log_dest & 0x0f)) { | |
372 | + set_bit(deliver_bitmask, i); | |
373 | + } | |
374 | + } | |
375 | + } | |
313 | 376 | } |
314 | 377 | } |
315 | - | |
316 | - return mask; | |
317 | 378 | } |
318 | 379 | |
319 | 380 | |
... | ... | @@ -356,23 +417,25 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, |
356 | 417 | uint8_t delivery_mode, uint8_t vector_num, |
357 | 418 | uint8_t polarity, uint8_t trigger_mode) |
358 | 419 | { |
359 | - uint32_t deliver_bitmask = 0; | |
420 | + uint32_t deliver_bitmask[MAX_APIC_WORDS]; | |
360 | 421 | int dest_shorthand = (s->icr[0] >> 18) & 3; |
361 | 422 | APICState *apic_iter; |
362 | 423 | |
363 | 424 | switch (dest_shorthand) { |
364 | - case 0: | |
365 | - deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode); | |
366 | - break; | |
367 | - case 1: | |
368 | - deliver_bitmask = (1 << s->id); | |
369 | - break; | |
370 | - case 2: | |
371 | - deliver_bitmask = 0xffffffff; | |
372 | - break; | |
373 | - case 3: | |
374 | - deliver_bitmask = 0xffffffff & ~(1 << s->id); | |
375 | - break; | |
425 | + case 0: | |
426 | + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); | |
427 | + break; | |
428 | + case 1: | |
429 | + memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); | |
430 | + set_bit(deliver_bitmask, s->id); | |
431 | + break; | |
432 | + case 2: | |
433 | + memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); | |
434 | + break; | |
435 | + case 3: | |
436 | + memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); | |
437 | + reset_bit(deliver_bitmask, s->id); | |
438 | + break; | |
376 | 439 | } |
377 | 440 | |
378 | 441 | switch (delivery_mode) { |
... | ... | @@ -381,24 +444,16 @@ static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, |
381 | 444 | int trig_mode = (s->icr[0] >> 15) & 1; |
382 | 445 | int level = (s->icr[0] >> 14) & 1; |
383 | 446 | if (level == 0 && trig_mode == 1) { |
384 | - for (apic_iter = first_local_apic; apic_iter != NULL; | |
385 | - apic_iter = apic_iter->next_apic) { | |
386 | - if (deliver_bitmask & (1 << apic_iter->id)) { | |
387 | - apic_iter->arb_id = apic_iter->id; | |
388 | - } | |
389 | - } | |
447 | + foreach_apic(apic_iter, deliver_bitmask, | |
448 | + apic_iter->arb_id = apic_iter->id ); | |
390 | 449 | return; |
391 | 450 | } |
392 | 451 | } |
393 | 452 | break; |
394 | 453 | |
395 | 454 | case APIC_DM_SIPI: |
396 | - for (apic_iter = first_local_apic; apic_iter != NULL; | |
397 | - apic_iter = apic_iter->next_apic) { | |
398 | - if (deliver_bitmask & (1 << apic_iter->id)) { | |
399 | - apic_startup(apic_iter, vector_num); | |
400 | - } | |
401 | - } | |
455 | + foreach_apic(apic_iter, deliver_bitmask, | |
456 | + apic_startup(apic_iter, vector_num) ); | |
402 | 457 | return; |
403 | 458 | } |
404 | 459 | |
... | ... | @@ -749,6 +804,8 @@ int apic_init(CPUState *env) |
749 | 804 | { |
750 | 805 | APICState *s; |
751 | 806 | |
807 | + if (last_apic_id >= MAX_APICS) | |
808 | + return -1; | |
752 | 809 | s = qemu_mallocz(sizeof(APICState)); |
753 | 810 | if (!s) |
754 | 811 | return -1; |
... | ... | @@ -772,10 +829,8 @@ int apic_init(CPUState *env) |
772 | 829 | |
773 | 830 | register_savevm("apic", 0, 1, apic_save, apic_load, s); |
774 | 831 | qemu_register_reset(apic_reset, s); |
775 | - | |
776 | - s->next_apic = first_local_apic; | |
777 | - first_local_apic = s; | |
778 | 832 | |
833 | + local_apics[s->id] = s; | |
779 | 834 | return 0; |
780 | 835 | } |
781 | 836 | |
... | ... | @@ -790,6 +845,7 @@ static void ioapic_service(IOAPICState *s) |
790 | 845 | uint8_t dest; |
791 | 846 | uint8_t dest_mode; |
792 | 847 | uint8_t polarity; |
848 | + uint32_t deliver_bitmask[MAX_APIC_WORDS]; | |
793 | 849 | |
794 | 850 | for (i = 0; i < IOAPIC_NUM_PINS; i++) { |
795 | 851 | mask = 1 << i; |
... | ... | @@ -807,8 +863,10 @@ static void ioapic_service(IOAPICState *s) |
807 | 863 | vector = pic_read_irq(isa_pic); |
808 | 864 | else |
809 | 865 | vector = entry & 0xff; |
810 | - apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode), | |
811 | - delivery_mode, vector, polarity, trig_mode); | |
866 | + | |
867 | + apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); | |
868 | + apic_bus_deliver(deliver_bitmask, delivery_mode, | |
869 | + vector, polarity, trig_mode); | |
812 | 870 | } |
813 | 871 | } |
814 | 872 | } | ... | ... |
vl.c
... | ... | @@ -153,10 +153,12 @@ 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 | |
156 | +#if defined(TARGET_SPARC) | |
157 | 157 | #define MAX_CPUS 16 |
158 | +#elif defined(TARGET_I386) | |
159 | +#define MAX_CPUS 255 | |
158 | 160 | #else |
159 | -#define MAX_CPUS 8 | |
161 | +#define MAX_CPUS 1 | |
160 | 162 | #endif |
161 | 163 | |
162 | 164 | /***********************************************************/ | ... | ... |