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 | /***********************************************************/ | ... | ... |