Warning, cross-references for /kernel/smp/smp.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "arch/i386.h"
0019 #include "arch/i386-percpu.h"
0020 #include "kernel.h"
0021 #include "mem/mem.h"
0022 #include "smp/smp.h"
0023 #include "smp/apic.h"
0024 #include "smp/spinlock.h"
0025 #include "drivers/acpi/acpi.h"
0026 #include "drivers/acpi/acmacros.h"
0027 #include "drivers/acpi/acexcep.h"
0028 #include "util/printf.h"
0029 #include "util/perfmon.h"
0030 #include "sched/sched.h"
0031
0032
0033
0034 volatile bool mp_enabled = 0;
0035 uint32 mp_num_cpus = 1;
0036 bool mp_apic_mode = 0;
0037 bool mp_ISA_PC = 0;
0038
0039 mp_int_override mp_overrides[MAX_INT_OVERRIDES];
0040 uint32 mp_num_overrides = 0;
0041
0042 uint32
0043 IRQ_to_GSI (uint32 src_bus, uint32 src_irq)
0044 {
0045
0046 int i;
0047 for (i = 0; i < mp_num_overrides; i++) {
0048 if (src_bus == mp_overrides[i].src_bus &&
0049 src_irq == mp_overrides[i].src_IRQ)
0050 return mp_overrides[i].dest_GSI;
0051 }
0052 if (src_bus != mp_ISA_bus_id)
0053 panic ("IRQ_to_GSI only implemented for ISA bus.");
0054
0055 return src_irq;
0056 }
0057
0058
0059
0060 uint8 CPU_to_APIC[MAX_CPUS];
0061 uint8 APIC_to_CPU[MAX_CPUS];
0062
0063 bool mp_ACPI_enabled = 0;
0064
0065
0066
0067
0068 uint32 mp_timer_IOAPIC_irq = 0;
0069 uint32 mp_timer_IOAPIC_id = 0;
0070 uint32 mp_ISA_bus_id = 0;
0071
0072
0073
0074
0075
0076
0077 int
0078 smp_init (void)
0079 {
0080 uint32 phys_id, log_dest;
0081 uint32 intel_mps_init(bool);
0082 uint32 acpi_early_init(void);
0083 void LAPIC_measure_timer(void);
0084 void LAPIC_init(void);
0085
0086 mp_apic_mode = 1;
0087
0088 LAPIC_init();
0089
0090 phys_id = get_pcpu_id();
0091
0092
0093 log_dest = 0x01000000 << phys_id;
0094 LAPIC_set_logical_destination(log_dest);
0095
0096
0097
0098 LAPIC_measure_timer ();
0099
0100
0101 #ifdef NO_ACPI
0102 if (0);
0103 #else
0104 if ((acpi_early_init()) > 0) {
0105
0106 mp_ACPI_enabled = 1;
0107 }
0108 #endif
0109
0110 #ifdef NO_INTEL_MPS
0111 else if (0);
0112 #else
0113 else if ((intel_mps_init(FALSE)) > 0) {
0114
0115 }
0116 #endif
0117
0118 else {
0119
0120 mp_apic_mode = 0;
0121 com1_printf ("Disabling APIC mode -- assuming ISA bus-only\n");
0122 mp_ISA_PC = 1;
0123 mp_num_cpus = 1;
0124 return 1;
0125 }
0126
0127 return mp_num_cpus;
0128 }
0129
0130 void
0131 smp_secondary_init (void)
0132 {
0133 void acpi_secondary_init(void);
0134 void IOAPIC_init(void);
0135
0136 if (!mp_ISA_PC)
0137 IOAPIC_init();
0138
0139 if(mp_ACPI_enabled)
0140 acpi_secondary_init();
0141
0142
0143
0144
0145
0146 }
0147
0148 void
0149 smp_enable_scheduling (void)
0150 {
0151 LAPIC_enable_timer(0x3e,
0152 FALSE,
0153 1);
0154
0155 LAPIC_start_timer(cpu_bus_freq / QUANTUM_HZ);
0156
0157 sched_enabled = 1;
0158 }
0159
0160
0161
0162
0163
0164
0165
0166 extern uint8 patch_code_start[];
0167 extern uint8 patch_code_end[];
0168 extern uint8 status_code[];
0169 extern uint8 ap_stack_ptr[];
0170
0171
0172
0173 uint32
0174 smp_boot_cpu (uint8 apic_id, uint8 APIC_version)
0175 {
0176 int success = 1;
0177 volatile int to;
0178 uint32 bootaddr, accept_status;
0179
0180
0181 uint32 page_frame = (uint32) alloc_phys_frame ();
0182 uint32 *virt_addr = map_virtual_page (page_frame | 3);
0183
0184
0185 #define TEST_BOOTED(x) (*((volatile uint32 *)(x+status_code-patch_code_start)))
0186 #define STACK_PTR(x) (*((volatile uint32 *)(x+ap_stack_ptr-patch_code_start)))
0187
0188
0189 bootaddr = MP_BOOTADDR;
0190 memcpy ((uint8 *) bootaddr, patch_code_start,
0191 patch_code_end - patch_code_start);
0192
0193 TEST_BOOTED (bootaddr) = 0;
0194
0195 STACK_PTR (bootaddr) = (uint32) virt_addr;
0196
0197
0198
0199
0200
0201
0202 accept_status = LAPIC_clear_error();
0203
0204
0205 LAPIC_send_ipi (apic_id,
0206 LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT);
0207
0208
0209 LAPIC_send_ipi (apic_id, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
0210
0211 tsc_delay_usec (10000);
0212
0213
0214 if (APIC_version >= APIC_VER_NEW) {
0215 int i;
0216 for (i = 1; i <= 2; i++) {
0217
0218
0219
0220
0221 if (TEST_BOOTED (bootaddr))
0222 break;
0223 LAPIC_send_ipi (apic_id, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
0224 tsc_delay_usec (200);
0225 }
0226 }
0227 #define LOOPS_TO_WAIT 10000000
0228
0229 to = 0;
0230 while (!TEST_BOOTED (bootaddr) && to++ < LOOPS_TO_WAIT) {
0231 tsc_delay_usec (200);
0232 }
0233 if (to >= LOOPS_TO_WAIT) {
0234 success = 0;
0235 }
0236
0237
0238 accept_status = LAPIC_clear_error();
0239
0240 return success;
0241 }
0242
0243
0244
0245
0246
0247
0248
0249 void
0250 ap_init (void)
0251 {
0252 int phys_id, log_dest;
0253 void LAPIC_init(void);
0254
0255
0256 LAPIC_init();
0257 LAPIC_set_task_priority(0x20);
0258
0259 phys_id = get_pcpu_id ();
0260
0261
0262 log_dest = 0x01000000 << phys_id;
0263 LAPIC_set_logical_destination(log_dest);
0264
0265 asm volatile ("lidt idt_ptr");
0266
0267
0268
0269 while (!mp_enabled)
0270 asm volatile ("pause");
0271
0272 LAPIC_enable_timer(0x3e, FALSE, 1);
0273 LAPIC_start_timer(cpu_bus_freq / QUANTUM_HZ);
0274
0275
0276
0277 lock_kernel ();
0278
0279
0280 perfmon_init ();
0281
0282
0283 hw_ltr (cpuTSS_selector[phys_id]);
0284
0285
0286 { void vmx_processor_init (void); vmx_processor_init (); }
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 ltr (idleTSS_selector[phys_id]);
0298
0299
0300 asm volatile ("jmp _sw_init_task":
0301 :"D" (lookup_TSS (idleTSS_selector[phys_id])));
0302
0303
0304
0305 panic ("AP: unreachable");
0306 }
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317